├── website
├── static
│ └── .nojekyll
├── CNAME
├── .npmrc
├── docs
│ ├── api
│ │ ├── __meta__.md
│ │ ├── clearEscapeEffect.md
│ │ ├── setGlobal.md
│ │ ├── setOptioins.md
│ │ ├── getGlobal.md
│ │ ├── channel.md
│ │ └── api.md
│ ├── blog
│ │ └── __meta__.md
│ ├── guide
│ │ ├── advance
│ │ │ └── __meta__.md
│ │ ├── concept
│ │ │ └── __meta__.md
│ │ ├── demo
│ │ │ ├── __meta__.md
│ │ │ └── demo.md
│ │ └── quickStart
│ │ │ └── __meta__.md
│ └── plugins
│ │ ├── __meta__.md
│ │ ├── plugins.md
│ │ └── es-module.md
├── babel.config.js
├── i18n
│ ├── en
│ │ └── docusaurus-plugin-content-docs
│ │ │ ├── current
│ │ │ ├── guide
│ │ │ │ ├── start
│ │ │ │ │ └── __meta__.md
│ │ │ │ ├── develop
│ │ │ │ │ └── __meta__.md
│ │ │ │ └── advance
│ │ │ │ │ └── __meta__.md
│ │ │ ├── community
│ │ │ │ └── discuss.md
│ │ │ ├── api
│ │ │ │ └── index.md
│ │ │ └── issues
│ │ │ │ └── multipleApp.md
│ │ │ └── current.json
│ └── zh
│ │ ├── docusaurus-theme-classic
│ │ ├── footer.json
│ │ └── navbar.json
│ │ └── docusaurus-plugin-content-docs
│ │ └── current.json
├── src
│ ├── components
│ │ ├── sumarryImg
│ │ │ └── index.jsx
│ │ ├── config
│ │ │ ├── _protectVariable.mdx
│ │ │ ├── _basename.mdx
│ │ │ ├── _viteConfig.mdx
│ │ │ ├── _insulationVariable.mdx
│ │ │ └── _domGetter.mdx
│ │ ├── Highlight
│ │ │ └── index.js
│ │ └── lifeCycle
│ │ │ ├── _onNotMatchRouter.mdx
│ │ │ ├── _afterUnmount.mdx
│ │ │ ├── _afterLoad.mdx
│ │ │ ├── _beforeLoad.mdx
│ │ │ ├── _beforeUnmount.mdx
│ │ │ ├── _errorUnmountApp.mdx
│ │ │ ├── _errorLoadApp.mdx
│ │ │ ├── _errorMountApp.mdx
│ │ │ ├── _afterEval.mdx
│ │ │ ├── _beforeMount.mdx
│ │ │ ├── _afterMount.mdx
│ │ │ └── _beforeEval.mdx
│ └── README.md
├── plugin
│ └── slardar
│ │ └── index.js
├── .gitignore
├── README.md
├── .editorconfig
└── CHANGELOG.md
├── dev
├── app-angular
│ ├── src
│ │ ├── assets
│ │ │ └── .gitkeep
│ │ ├── app
│ │ │ ├── app.component.css
│ │ │ ├── home
│ │ │ │ ├── home.component.css
│ │ │ │ ├── home.component.html
│ │ │ │ └── home.component.ts
│ │ │ ├── dashboard
│ │ │ │ ├── dashboard.component.css
│ │ │ │ ├── dashboard.component.html
│ │ │ │ └── dashboard.component.ts
│ │ │ ├── pageNotFound
│ │ │ │ ├── pageNotFound.component.css
│ │ │ │ ├── pageNotFound.component.html
│ │ │ │ └── pageNotFound.component.ts
│ │ │ ├── productList
│ │ │ │ ├── productList.component.css
│ │ │ │ ├── productList.component.html
│ │ │ │ └── productList.component.ts
│ │ │ ├── topBar
│ │ │ │ ├── topBar.component.css
│ │ │ │ ├── topBar.component.ts
│ │ │ │ └── topBar.component.html
│ │ │ ├── app.component.ts
│ │ │ ├── product.ts
│ │ │ └── app.component.spec.ts
│ │ ├── styles.less
│ │ ├── environments
│ │ │ ├── environment.prod.ts
│ │ │ └── environment.ts
│ │ ├── favicon.ico
│ │ ├── typings
│ │ │ └── index.d.ts
│ │ ├── index.html
│ │ ├── main.ts
│ │ └── test.ts
│ ├── .editorconfig
│ ├── e2e
│ │ ├── tsconfig.json
│ │ ├── src
│ │ │ ├── app.po.ts
│ │ │ └── app.e2e-spec.ts
│ │ └── protractor.conf.js
│ ├── tsconfig.app.json
│ ├── tsconfig.spec.json
│ ├── tsconfig.json
│ ├── .browserslistrc
│ ├── README.md
│ └── karma.conf.js
├── app-react-16
│ ├── public
│ │ ├── dynamic.js
│ │ └── index.html
│ ├── webpack.config.babel.js
│ ├── src
│ │ ├── PageNotFound.tsx
│ │ ├── ErrorBoundary.tsx
│ │ ├── reportWebVitals.js
│ │ ├── App.less
│ │ └── index.tsx
│ ├── typings.d.ts
│ ├── .babelrc
│ └── tsconfig.json
├── app-main
│ ├── src
│ │ ├── components
│ │ │ ├── Link
│ │ │ │ ├── index.less
│ │ │ │ └── index.tsx
│ │ │ ├── loadApp
│ │ │ │ ├── index.less
│ │ │ │ └── loadAppFunc.tsx
│ │ │ ├── root
│ │ │ │ └── index.less
│ │ │ └── PageNotFound
│ │ │ │ └── index.tsx
│ │ ├── static
│ │ │ ├── favicon.ico
│ │ │ ├── img
│ │ │ │ └── Garfish.png
│ │ │ └── icons
│ │ │ │ ├── Angular.svg
│ │ │ │ ├── Vue.svg
│ │ │ │ └── New.svg
│ │ ├── less
│ │ │ └── variable.less
│ │ ├── index.tsx
│ │ ├── store.ts
│ │ └── garfishInit.ts
│ ├── webpack.config.babel.js
│ ├── public
│ │ ├── favicon.ico
│ │ └── index.html
│ ├── typings.d.ts
│ ├── .babelrc
│ └── tsconfig.json
├── app-react-17
│ ├── src
│ │ ├── components
│ │ │ ├── Link
│ │ │ │ ├── index.less
│ │ │ │ └── index.tsx
│ │ │ ├── lazyComponent.tsx
│ │ │ ├── PageNotFound.tsx
│ │ │ ├── ErrorBoundary.tsx
│ │ │ └── detail
│ │ │ │ ├── index.less
│ │ │ │ └── index.tsx
│ │ ├── less
│ │ │ └── variable.less
│ │ ├── reportWebVitals.js
│ │ └── constant.ts
│ ├── webpack.config.babel.js
│ ├── public
│ │ └── index.html
│ ├── typings.d.ts
│ ├── .babelrc
│ └── tsconfig.json
├── app-vue-vite
│ ├── .env.production
│ ├── .env
│ ├── public
│ │ └── favicon.ico
│ ├── src
│ │ ├── assets
│ │ │ └── logo.png
│ │ ├── shimsVue.d.ts
│ │ ├── main.ts
│ │ ├── App.vue
│ │ └── components
│ │ │ └── HelloWorld.vue
│ ├── index.html
│ ├── README.md
│ ├── package.json
│ └── vite.config.ts
├── app-react-18
│ ├── webpack.config.babel.js
│ ├── public
│ │ └── index.html
│ ├── src
│ │ ├── PageNotFound.tsx
│ │ ├── ErrorBoundary.tsx
│ │ ├── reportWebVitals.js
│ │ ├── root.tsx
│ │ └── App.less
│ ├── typings.d.ts
│ ├── .babelrc
│ └── tsconfig.json
├── app-vue-2
│ ├── babel.config.js
│ ├── public
│ │ ├── favicon.ico
│ │ ├── index.html
│ │ └── remoteModule.js
│ ├── src
│ │ ├── assets
│ │ │ └── logo.png
│ │ ├── store
│ │ │ ├── index.js
│ │ │ └── store.js
│ │ ├── shimsVue.d.ts
│ │ └── components
│ │ │ ├── HelloGarfish.vue
│ │ │ └── alertError.vue
│ ├── README.md
│ ├── vue.config.js
│ └── tsconfig.json
├── app-vue
│ ├── babel.config.js
│ ├── public
│ │ ├── favicon.ico
│ │ ├── index.html
│ │ └── remoteModule.js
│ ├── src
│ │ ├── assets
│ │ │ └── logo.png
│ │ ├── store
│ │ │ ├── index.js
│ │ │ └── store.js
│ │ ├── App.vue
│ │ └── components
│ │ │ └── HelloWorld.vue
│ ├── README.md
│ ├── vue.config.js
│ └── tsconfig.json
├── app-vue-3
│ ├── public
│ │ ├── favicon.ico
│ │ └── index.html
│ ├── src
│ │ ├── assets
│ │ │ └── logo.png
│ │ ├── shimsVue.d.ts
│ │ ├── components
│ │ │ ├── HelloGarfish.vue
│ │ │ └── alertError.vue
│ │ └── store.js
│ ├── README.md
│ ├── vue.config.js
│ └── tsconfig.json
├── app-esm
│ ├── package.json
│ └── src
│ │ ├── index.js
│ │ └── index.html
├── util.js
└── config.json
├── .npmrc
├── cypress.json
├── packages
├── test-suite
│ ├── src
│ │ └── index.ts
│ └── tsup.config.ts
├── bridge-vue-v2
│ ├── src
│ │ ├── index.ts
│ │ └── types.d.ts
│ ├── tsup.config.ts
│ └── LICENSE
├── bridge-vue-v3
│ ├── src
│ │ ├── index.ts
│ │ └── types.d.ts
│ ├── tsup.config.ts
│ ├── README.md
│ └── LICENSE
├── es-module
│ ├── __tests__
│ │ └── case
│ │ │ ├── importCheck
│ │ │ ├── m3.js
│ │ │ ├── m2.js
│ │ │ └── m1.js
│ │ │ ├── exportNamespace
│ │ │ ├── m4.js
│ │ │ ├── m5.js
│ │ │ ├── m3.js
│ │ │ ├── m2.js
│ │ │ └── m1.js
│ │ │ ├── variableCheck
│ │ │ └── m2.js
│ │ │ ├── dynamicImport
│ │ │ ├── m2.js
│ │ │ └── m1.js
│ │ │ ├── executionOrder
│ │ │ ├── m2.js
│ │ │ ├── m3.js
│ │ │ └── m1.js
│ │ │ ├── strictModeCheck
│ │ │ └── m1.js
│ │ │ ├── resourceRedirect
│ │ │ └── m1.js
│ │ │ ├── importMeta
│ │ │ └── m1.js
│ │ │ ├── circularReference
│ │ │ ├── m2.js
│ │ │ └── m1.js
│ │ │ └── exportDeclaration
│ │ │ ├── m2.js
│ │ │ └── m1.js
│ ├── .npmignore
│ ├── src
│ │ └── index.ts
│ ├── tsup.config.ts
│ ├── README.md
│ └── LICENSE
├── garfish
│ ├── __tests__
│ │ ├── resources
│ │ │ ├── dynamic.js
│ │ │ ├── vueIndex.js
│ │ │ ├── reactApp.html
│ │ │ └── vueApp.html
│ │ └── __snapshots__
│ │ │ └── run.spec.ts.snap
│ ├── .npmignore
│ ├── tsup.config.ts
│ ├── src
│ │ └── index.ts
│ ├── index.d.ts
│ ├── README.md
│ └── LICENSE
├── core
│ ├── .npmignore
│ ├── src
│ │ ├── index.ts
│ │ └── plugins
│ │ │ ├── lifecycle.ts
│ │ │ └── performance
│ │ │ └── index.ts
│ ├── tsup.config.ts
│ ├── __tests__
│ │ ├── __snapshots__
│ │ │ └── preloadPlugin.spec.ts.snap
│ │ └── resources
│ │ │ ├── reactApp.html
│ │ │ ├── vueApp.html
│ │ │ ├── vue3App.html
│ │ │ └── asyncProviderApp.html
│ └── LICENSE
├── hooks
│ ├── .npmignore
│ ├── tsup.config.ts
│ ├── src
│ │ ├── index.ts
│ │ ├── asyncHook.ts
│ │ └── syncHook.ts
│ ├── README.md
│ └── package.json
├── loader
│ ├── .npmignore
│ ├── tsup.config.ts
│ ├── src
│ │ ├── managers
│ │ │ └── module.ts
│ │ └── utils.ts
│ ├── LICENSE
│ └── package.json
├── router
│ ├── .npmignore
│ ├── tsup.config.ts
│ ├── README.md
│ ├── src
│ │ └── utils
│ │ │ └── index.ts
│ ├── LICENSE
│ └── package.json
├── utils
│ ├── .npmignore
│ ├── tsup.config.ts
│ ├── src
│ │ ├── logger.ts
│ │ ├── index.ts
│ │ └── garfish.ts
│ ├── README.md
│ └── LICENSE
├── browser-vm
│ ├── .npmignore
│ ├── src
│ │ ├── index.ts
│ │ ├── symbolTypes.ts
│ │ ├── modules
│ │ │ ├── uiEvent.ts
│ │ │ └── mutationObserver.ts
│ │ ├── dynamicNode
│ │ │ └── processParams.ts
│ │ ├── lifecycle.ts
│ │ └── types.ts
│ ├── __tests__
│ │ ├── resources
│ │ │ ├── links
│ │ │ │ ├── suffix.css
│ │ │ │ ├── no-suffix
│ │ │ │ └── no-content-type-suffix
│ │ │ └── scripts
│ │ │ │ ├── jsonp
│ │ │ │ ├── no-type-jsonp
│ │ │ │ ├── content-type-jsonp
│ │ │ │ └── event-task.js
│ │ └── modules
│ │ │ └── uiEvent.spec.ts
│ ├── tsup.config.ts
│ └── LICENSE
├── browser-snapshot
│ ├── .npmignore
│ ├── tsup.config.ts
│ ├── README.md
│ ├── __tests__
│ │ ├── __snapshots__
│ │ │ ├── sandbox.spec.ts.snap
│ │ │ ├── window.spec.ts.snap
│ │ │ └── style.spec.ts.snap
│ │ ├── event.spec.ts
│ │ └── sandbox.spec.ts
│ ├── src
│ │ ├── patchers
│ │ │ ├── history.ts
│ │ │ ├── webpackjsonp.ts
│ │ │ ├── multithread.ts
│ │ │ └── interval.ts
│ │ └── globalExtensions.ts
│ └── LICENSE
├── remote-module
│ ├── .npmignore
│ ├── tsup.config.ts
│ ├── src
│ │ ├── apis
│ │ │ ├── esModule.ts
│ │ │ └── preload.ts
│ │ ├── index.ts
│ │ ├── hooks.ts
│ │ └── actuator.ts
│ └── LICENSE
├── bridge-react-v18
│ ├── src
│ │ └── index.ts
│ ├── tsup.config.ts
│ ├── README.md
│ └── LICENSE
├── bridge-react
│ ├── src
│ │ └── index.ts
│ ├── tsup.config.ts
│ ├── README.md
│ └── LICENSE
└── global.d.ts
├── renovate.json
├── pnpm-workspace.yaml
├── .husky
├── pre-commit
└── commit-msg
├── scripts
├── devCypress.js
├── utils.js
├── e2e.js
└── verifyCommit.js
├── .prettierrc
├── cypress
├── fixtures
│ └── example.json
├── plugins
│ └── index.js
├── support
│ ├── index.js
│ └── commands.js
└── integration
│ ├── common.js
│ └── 2-the-vm-sandbox
│ └── set-global-variable.spec.js
├── .editorconfig
├── .github
└── ISSUE_TEMPLATE
│ └── config.yml
├── babel.config.js
├── .pnpmfile.cjs
├── .ls-lint.yml
├── .gitignore
├── tsconfig.json
└── jest.config.js
/website/static/.nojekyll:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/website/CNAME:
--------------------------------------------------------------------------------
1 | garfishjs.org
2 |
--------------------------------------------------------------------------------
/dev/app-angular/src/assets/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/dev/app-react-16/public/dynamic.js:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/dev/app-angular/src/app/app.component.css:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/dev/app-main/src/components/Link/index.less:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.npmrc:
--------------------------------------------------------------------------------
1 | registry=https://registry.npmjs.org
2 |
--------------------------------------------------------------------------------
/dev/app-angular/src/app/home/home.component.css:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/dev/app-react-17/src/components/Link/index.less:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/cypress.json:
--------------------------------------------------------------------------------
1 | {
2 | "projectId": "yren6i"
3 | }
4 |
--------------------------------------------------------------------------------
/dev/app-vue-vite/.env.production:
--------------------------------------------------------------------------------
1 | VITE_APP_BASE=''
2 |
--------------------------------------------------------------------------------
/dev/app-angular/src/app/dashboard/dashboard.component.css:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/website/.npmrc:
--------------------------------------------------------------------------------
1 | registry = 'https://registry.npmjs.org'
2 |
--------------------------------------------------------------------------------
/dev/app-angular/src/app/pageNotFound/pageNotFound.component.css:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/dev/app-angular/src/app/productList/productList.component.css:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/test-suite/src/index.ts:
--------------------------------------------------------------------------------
1 | export * from './mock';
2 |
--------------------------------------------------------------------------------
/dev/app-vue-vite/.env:
--------------------------------------------------------------------------------
1 | VITE_APP_BASE='http://localhost:8091/'
2 |
--------------------------------------------------------------------------------
/dev/app-angular/src/app/home/home.component.html:
--------------------------------------------------------------------------------
1 |
This is Home.
2 |
--------------------------------------------------------------------------------
/dev/app-angular/src/styles.less:
--------------------------------------------------------------------------------
1 | .link {
2 | position: relative;
3 | }
4 |
--------------------------------------------------------------------------------
/renovate.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": [
3 | "config:base"
4 | ]
5 | }
6 |
--------------------------------------------------------------------------------
/packages/bridge-vue-v2/src/index.ts:
--------------------------------------------------------------------------------
1 | export { vueBridge } from './vueBridge';
2 |
--------------------------------------------------------------------------------
/packages/bridge-vue-v3/src/index.ts:
--------------------------------------------------------------------------------
1 | export { vueBridge } from './vueBridge';
2 |
--------------------------------------------------------------------------------
/packages/es-module/__tests__/case/importCheck/m3.js:
--------------------------------------------------------------------------------
1 | export const _name = 'm2';
2 |
--------------------------------------------------------------------------------
/packages/garfish/__tests__/resources/dynamic.js:
--------------------------------------------------------------------------------
1 | const hello = 'Hello World';
2 |
--------------------------------------------------------------------------------
/packages/es-module/__tests__/case/exportNamespace/m4.js:
--------------------------------------------------------------------------------
1 | export const name = 'm4';
2 |
--------------------------------------------------------------------------------
/packages/es-module/__tests__/case/importCheck/m2.js:
--------------------------------------------------------------------------------
1 | export { name } from './m3.js';
2 |
--------------------------------------------------------------------------------
/packages/es-module/__tests__/case/variableCheck/m2.js:
--------------------------------------------------------------------------------
1 | export const name = ['m2'];
2 |
--------------------------------------------------------------------------------
/dev/app-main/webpack.config.babel.js:
--------------------------------------------------------------------------------
1 | module.exports = require('./webpack.config.js');
2 |
--------------------------------------------------------------------------------
/dev/app-react-16/webpack.config.babel.js:
--------------------------------------------------------------------------------
1 | module.exports = require('./webpack.config.js');
2 |
--------------------------------------------------------------------------------
/dev/app-react-17/webpack.config.babel.js:
--------------------------------------------------------------------------------
1 | module.exports = require('./webpack.config.js');
2 |
--------------------------------------------------------------------------------
/dev/app-react-18/webpack.config.babel.js:
--------------------------------------------------------------------------------
1 | module.exports = require('./webpack.config.js');
2 |
--------------------------------------------------------------------------------
/website/docs/api/__meta__.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: API
3 | collapsed: false
4 | order: 4
5 | ---
6 |
--------------------------------------------------------------------------------
/dev/app-angular/src/app/dashboard/dashboard.component.html:
--------------------------------------------------------------------------------
1 | This is Dashboard.
2 |
3 |
--------------------------------------------------------------------------------
/dev/app-angular/src/app/pageNotFound/pageNotFound.component.html:
--------------------------------------------------------------------------------
1 | Oops, 404...
2 |
--------------------------------------------------------------------------------
/dev/app-angular/src/app/productList/productList.component.html:
--------------------------------------------------------------------------------
1 | This is List.
2 |
3 |
--------------------------------------------------------------------------------
/pnpm-workspace.yaml:
--------------------------------------------------------------------------------
1 |
2 | packages:
3 | - 'packages/**'
4 | - 'dev/**'
5 | - 'website'
6 |
--------------------------------------------------------------------------------
/website/docs/blog/__meta__.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: blog
3 | collapsed: false
4 | order: 4
5 | ---
6 |
--------------------------------------------------------------------------------
/packages/core/.npmignore:
--------------------------------------------------------------------------------
1 | src/
2 | node_modules/
3 | __tests__/
4 | .npmignore
5 | tsup.config.ts
6 |
--------------------------------------------------------------------------------
/packages/garfish/.npmignore:
--------------------------------------------------------------------------------
1 | src/
2 | node_modules/
3 | __tests__/
4 | .npmignore
5 | tsup.config.ts
6 |
--------------------------------------------------------------------------------
/packages/hooks/.npmignore:
--------------------------------------------------------------------------------
1 | src/
2 | node_modules/
3 | __tests__/
4 | .npmignore
5 | tsup.config.ts
6 |
--------------------------------------------------------------------------------
/packages/loader/.npmignore:
--------------------------------------------------------------------------------
1 | src/
2 | node_modules/
3 | __tests__/
4 | .npmignore
5 | tsup.config.ts
6 |
--------------------------------------------------------------------------------
/packages/router/.npmignore:
--------------------------------------------------------------------------------
1 | src/
2 | node_modules/
3 | __tests__/
4 | .npmignore
5 | tsup.config.ts
6 |
--------------------------------------------------------------------------------
/packages/utils/.npmignore:
--------------------------------------------------------------------------------
1 | src/
2 | node_modules/
3 | __tests__/
4 | .npmignore
5 | tsup.config.ts
6 |
--------------------------------------------------------------------------------
/website/docs/guide/advance/__meta__.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: 进阶
3 | collapsed: true
4 | order: 5
5 | ---
6 |
--------------------------------------------------------------------------------
/website/docs/guide/concept/__meta__.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: 核心能力
3 | collapsed: true
4 | order: 4
5 | ---
6 |
--------------------------------------------------------------------------------
/website/docs/guide/demo/__meta__.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: 接入指南
3 | collapsed: true
4 | order: 3
5 | ---
6 |
--------------------------------------------------------------------------------
/.husky/pre-commit:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | . "$(dirname "$0")/_/husky.sh"
3 |
4 | npx ls-lint && npx lint-staged
5 |
--------------------------------------------------------------------------------
/dev/app-vue-2/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: ['@vue/cli-plugin-babel/preset'],
3 | };
4 |
--------------------------------------------------------------------------------
/dev/app-vue/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: ['@vue/cli-plugin-babel/preset'],
3 | };
4 |
--------------------------------------------------------------------------------
/packages/browser-vm/.npmignore:
--------------------------------------------------------------------------------
1 | src/
2 | node_modules/
3 | __tests__/
4 | .npmignore
5 | tsup.config.ts
6 |
--------------------------------------------------------------------------------
/packages/es-module/.npmignore:
--------------------------------------------------------------------------------
1 | src/
2 | node_modules/
3 | __tests__/
4 | .npmignore
5 | tsup.config.ts
6 |
--------------------------------------------------------------------------------
/packages/es-module/__tests__/case/dynamicImport/m2.js:
--------------------------------------------------------------------------------
1 | export const name = 'm2';
2 | export default [1];
3 |
--------------------------------------------------------------------------------
/packages/es-module/__tests__/case/importCheck/m1.js:
--------------------------------------------------------------------------------
1 | // name 不存在,会报错
2 | import { name } from './m3.js';
3 |
--------------------------------------------------------------------------------
/scripts/devCypress.js:
--------------------------------------------------------------------------------
1 | const { runAllExample } = require('./runE2eProject.js');
2 |
3 | runAllExample();
4 |
--------------------------------------------------------------------------------
/website/docs/guide/quickStart/__meta__.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: 快速上手
3 | collapsed: false
4 | order: 1
5 | ---
6 |
--------------------------------------------------------------------------------
/dev/app-vue/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jacob-lcs/garfish/HEAD/dev/app-vue/public/favicon.ico
--------------------------------------------------------------------------------
/packages/browser-snapshot/.npmignore:
--------------------------------------------------------------------------------
1 | src/
2 | node_modules/
3 | __tests__/
4 | .npmignore
5 | tsup.config.ts
6 |
--------------------------------------------------------------------------------
/packages/es-module/__tests__/case/exportNamespace/m5.js:
--------------------------------------------------------------------------------
1 | export * from './m3.js';
2 | export * from './m4.js';
3 |
--------------------------------------------------------------------------------
/packages/remote-module/.npmignore:
--------------------------------------------------------------------------------
1 | src/
2 | node_modules/
3 | __tests__/
4 | .npmignore
5 | tsup.config.ts
6 |
--------------------------------------------------------------------------------
/website/docs/plugins/__meta__.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: garfish-plugins
3 | collapsed: false
4 | order: 1
5 | ---
6 |
--------------------------------------------------------------------------------
/dev/app-angular/src/environments/environment.prod.ts:
--------------------------------------------------------------------------------
1 | export const environment = {
2 | production: true,
3 | };
4 |
--------------------------------------------------------------------------------
/dev/app-angular/src/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jacob-lcs/garfish/HEAD/dev/app-angular/src/favicon.ico
--------------------------------------------------------------------------------
/dev/app-main/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jacob-lcs/garfish/HEAD/dev/app-main/public/favicon.ico
--------------------------------------------------------------------------------
/dev/app-vue-2/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jacob-lcs/garfish/HEAD/dev/app-vue-2/public/favicon.ico
--------------------------------------------------------------------------------
/dev/app-vue-3/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jacob-lcs/garfish/HEAD/dev/app-vue-3/public/favicon.ico
--------------------------------------------------------------------------------
/dev/app-vue/src/assets/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jacob-lcs/garfish/HEAD/dev/app-vue/src/assets/logo.png
--------------------------------------------------------------------------------
/dev/app-main/src/static/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jacob-lcs/garfish/HEAD/dev/app-main/src/static/favicon.ico
--------------------------------------------------------------------------------
/dev/app-vue-2/src/assets/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jacob-lcs/garfish/HEAD/dev/app-vue-2/src/assets/logo.png
--------------------------------------------------------------------------------
/dev/app-vue-3/src/assets/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jacob-lcs/garfish/HEAD/dev/app-vue-3/src/assets/logo.png
--------------------------------------------------------------------------------
/dev/app-vue-vite/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jacob-lcs/garfish/HEAD/dev/app-vue-vite/public/favicon.ico
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "semi": true,
3 | "singleQuote": true,
4 | "printWidth": 80,
5 | "trailingComma": "all"
6 | }
7 |
8 |
--------------------------------------------------------------------------------
/dev/app-vue-vite/src/assets/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jacob-lcs/garfish/HEAD/dev/app-vue-vite/src/assets/logo.png
--------------------------------------------------------------------------------
/packages/es-module/__tests__/case/executionOrder/m2.js:
--------------------------------------------------------------------------------
1 | expect(globalThis.orderIndex).toBe(0);
2 | globalThis.orderIndex++;
3 |
--------------------------------------------------------------------------------
/packages/es-module/__tests__/case/executionOrder/m3.js:
--------------------------------------------------------------------------------
1 | expect(globalThis.orderIndex).toBe(1);
2 | globalThis.orderIndex++;
3 |
--------------------------------------------------------------------------------
/website/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: [require.resolve('@docusaurus/core/lib/babel/preset')],
3 | };
4 |
--------------------------------------------------------------------------------
/dev/app-main/src/static/img/Garfish.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jacob-lcs/garfish/HEAD/dev/app-main/src/static/img/Garfish.png
--------------------------------------------------------------------------------
/packages/bridge-react-v18/src/index.ts:
--------------------------------------------------------------------------------
1 | export { reactBridge } from './reactBridge';
2 | export type { PropsInfo } from './types';
3 |
--------------------------------------------------------------------------------
/packages/bridge-react/src/index.ts:
--------------------------------------------------------------------------------
1 | export { reactBridge } from './reactBridge';
2 | export type { PropsInfo } from './types';
3 |
--------------------------------------------------------------------------------
/packages/core/src/index.ts:
--------------------------------------------------------------------------------
1 | export type { interfaces } from './interface';
2 | export { Garfish as default } from './garfish';
3 |
--------------------------------------------------------------------------------
/packages/global.d.ts:
--------------------------------------------------------------------------------
1 | declare const __DEV__: boolean;
2 | declare const __TEST__: boolean;
3 | declare const __VERSION__: string;
4 |
--------------------------------------------------------------------------------
/website/docs/plugins/plugins.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Garfish 插件
3 | slug: /garfish-plugins
4 | order: 2
5 | ---
6 |
7 | ## Garfish 插件
8 |
--------------------------------------------------------------------------------
/.husky/commit-msg:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | . "$(dirname "$0")/_/husky.sh"
3 |
4 | export HUSKY_GIT_PARAMS=$1
5 | node scripts/verifyCommit.js
6 |
--------------------------------------------------------------------------------
/dev/app-main/src/components/loadApp/index.less:
--------------------------------------------------------------------------------
1 | .app-item {
2 | width: 50%;
3 | text-align: center;
4 | padding: 0 20px;
5 | }
6 |
--------------------------------------------------------------------------------
/dev/app-main/src/less/variable.less:
--------------------------------------------------------------------------------
1 | @import '../../node_modules/@arco-design/web-react/dist/css/index.less';
2 |
3 | @prefix: main-app;
--------------------------------------------------------------------------------
/packages/browser-vm/src/index.ts:
--------------------------------------------------------------------------------
1 | export { GarfishBrowserVm } from './pluginify';
2 | export { Sandbox as default } from './sandbox';
3 |
--------------------------------------------------------------------------------
/packages/es-module/src/index.ts:
--------------------------------------------------------------------------------
1 | export { Runtime as default } from './runtime';
2 | export { GarfishEsModule } from './pluginify';
3 |
--------------------------------------------------------------------------------
/packages/browser-vm/__tests__/resources/links/suffix.css:
--------------------------------------------------------------------------------
1 | /* suffix test case */
2 | #root{
3 | color: red;
4 | background: blue;
5 | }
6 |
--------------------------------------------------------------------------------
/packages/browser-vm/__tests__/resources/links/no-suffix:
--------------------------------------------------------------------------------
1 | /* no-suffix test case */
2 | #root{
3 | color: red;
4 | background: yellow;
5 | }
6 |
--------------------------------------------------------------------------------
/website/i18n/en/docusaurus-plugin-content-docs/current/guide/start/__meta__.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: guide
3 | collapsed: false
4 | order: 1
5 | ---
6 |
--------------------------------------------------------------------------------
/dev/app-react-17/src/less/variable.less:
--------------------------------------------------------------------------------
1 | @import '../../node_modules/@arco-design/web-react/dist/css/index.less';
2 |
3 | @prefix: sub-app-react17;
4 |
--------------------------------------------------------------------------------
/website/i18n/en/docusaurus-plugin-content-docs/current/guide/develop/__meta__.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Quick start
3 | collapsed: true
4 | order: 2
5 | ---
6 |
--------------------------------------------------------------------------------
/dev/app-main/src/components/root/index.less:
--------------------------------------------------------------------------------
1 | .loadApp-wrapper {
2 | display: flex;
3 | justify-content: space-around;
4 | padding-top: 60px;
5 | }
6 |
--------------------------------------------------------------------------------
/dev/app-react-17/src/components/lazyComponent.tsx:
--------------------------------------------------------------------------------
1 | export default function () {
2 | return React sub App lazyComponent
;
3 | }
4 |
--------------------------------------------------------------------------------
/packages/es-module/__tests__/case/strictModeCheck/m1.js:
--------------------------------------------------------------------------------
1 | function a() {
2 | return function b() {
3 | with ({}) {
4 | }
5 | };
6 | }
7 | a();
8 |
--------------------------------------------------------------------------------
/website/i18n/en/docusaurus-plugin-content-docs/current/guide/advance/__meta__.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Advanced features
3 | collapsed: true
4 | order: 3
5 | ---
6 |
--------------------------------------------------------------------------------
/packages/core/tsup.config.ts:
--------------------------------------------------------------------------------
1 | import pkg from './package.json';
2 | import { baseTsup } from '../../tsup.config';
3 |
4 | export const tsup = baseTsup(pkg);
5 |
--------------------------------------------------------------------------------
/packages/es-module/__tests__/case/exportNamespace/m3.js:
--------------------------------------------------------------------------------
1 | export const name = 'm3';
2 | export const a = [1];
3 | export const b = [2];
4 | export default [3];
5 |
--------------------------------------------------------------------------------
/packages/hooks/tsup.config.ts:
--------------------------------------------------------------------------------
1 | import pkg from './package.json';
2 | import { baseTsup } from '../../tsup.config';
3 |
4 | export const tsup = baseTsup(pkg);
5 |
--------------------------------------------------------------------------------
/packages/loader/tsup.config.ts:
--------------------------------------------------------------------------------
1 | import pkg from './package.json';
2 | import { baseTsup } from '../../tsup.config';
3 |
4 | export const tsup = baseTsup(pkg);
5 |
--------------------------------------------------------------------------------
/packages/router/tsup.config.ts:
--------------------------------------------------------------------------------
1 | import pkg from './package.json';
2 | import { baseTsup } from '../../tsup.config';
3 |
4 | export const tsup = baseTsup(pkg);
5 |
--------------------------------------------------------------------------------
/packages/utils/tsup.config.ts:
--------------------------------------------------------------------------------
1 | import pkg from './package.json';
2 | import { baseTsup } from '../../tsup.config';
3 |
4 | export const tsup = baseTsup(pkg);
5 |
--------------------------------------------------------------------------------
/packages/bridge-react/tsup.config.ts:
--------------------------------------------------------------------------------
1 | import pkg from './package.json';
2 | import { baseTsup } from '../../tsup.config';
3 |
4 | export const tsup = baseTsup(pkg);
5 |
--------------------------------------------------------------------------------
/packages/browser-vm/tsup.config.ts:
--------------------------------------------------------------------------------
1 | import pkg from './package.json';
2 | import { baseTsup } from '../../tsup.config';
3 |
4 | export const tsup = baseTsup(pkg);
5 |
--------------------------------------------------------------------------------
/packages/es-module/tsup.config.ts:
--------------------------------------------------------------------------------
1 | import pkg from './package.json';
2 | import { baseTsup } from '../../tsup.config';
3 |
4 | export const tsup = baseTsup(pkg);
5 |
--------------------------------------------------------------------------------
/packages/test-suite/tsup.config.ts:
--------------------------------------------------------------------------------
1 | import pkg from './package.json';
2 | import { baseTsup } from '../../tsup.config';
3 |
4 | export const tsup = baseTsup(pkg);
5 |
--------------------------------------------------------------------------------
/packages/bridge-react-v18/tsup.config.ts:
--------------------------------------------------------------------------------
1 | import pkg from './package.json';
2 | import { baseTsup } from '../../tsup.config';
3 |
4 | export const tsup = baseTsup(pkg);
5 |
--------------------------------------------------------------------------------
/packages/bridge-vue-v2/tsup.config.ts:
--------------------------------------------------------------------------------
1 | import pkg from './package.json';
2 | import { baseTsup } from '../../tsup.config';
3 |
4 | export const tsup = baseTsup(pkg);
5 |
--------------------------------------------------------------------------------
/packages/bridge-vue-v3/tsup.config.ts:
--------------------------------------------------------------------------------
1 | import pkg from './package.json';
2 | import { baseTsup } from '../../tsup.config';
3 |
4 | export const tsup = baseTsup(pkg);
5 |
--------------------------------------------------------------------------------
/packages/browser-snapshot/tsup.config.ts:
--------------------------------------------------------------------------------
1 | import pkg from './package.json';
2 | import { baseTsup } from '../../tsup.config';
3 |
4 | export const tsup = baseTsup(pkg);
5 |
--------------------------------------------------------------------------------
/packages/remote-module/tsup.config.ts:
--------------------------------------------------------------------------------
1 | import pkg from './package.json';
2 | import { baseTsup } from '../../tsup.config';
3 |
4 | export const tsup = baseTsup(pkg);
5 |
--------------------------------------------------------------------------------
/dev/app-angular/src/typings/index.d.ts:
--------------------------------------------------------------------------------
1 | export {};
2 | declare global {
3 | interface Window {
4 | __GARFISH__: boolean;
5 | __GARFISH_EXPORTS__: any;
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/packages/browser-vm/__tests__/resources/links/no-content-type-suffix:
--------------------------------------------------------------------------------
1 | /* no-content-type-suffix test case */
2 | #root{
3 | color: red;
4 | background: gray;
5 | }
6 |
7 |
--------------------------------------------------------------------------------
/website/docs/plugins/es-module.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Garfish es-module plugins
3 | slug: /garfish-plugins/es-module.md
4 | order: 1
5 | ---
6 |
7 | ## garfish es-module plugin
8 |
--------------------------------------------------------------------------------
/packages/browser-vm/__tests__/resources/scripts/jsonp:
--------------------------------------------------------------------------------
1 |
2 | const testInfo = {
3 | key: 'jsonpVariable',
4 | value: true
5 | };
6 |
7 | window[testInfo.key] = testInfo.value;
8 |
--------------------------------------------------------------------------------
/packages/browser-vm/__tests__/resources/scripts/no-type-jsonp:
--------------------------------------------------------------------------------
1 |
2 | const testInfo = {
3 | key: 'noTypeJsonp',
4 | value: true
5 | };
6 |
7 | window[testInfo.key] = testInfo.value;
8 |
--------------------------------------------------------------------------------
/dev/app-vue-2/src/store/index.js:
--------------------------------------------------------------------------------
1 | import store from './store';
2 | import Vue from 'vue';
3 | import Vuex from 'vuex';
4 |
5 | Vue.use(Vuex);
6 |
7 | export default new Vuex.Store(store);
8 |
--------------------------------------------------------------------------------
/dev/app-vue/src/store/index.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue';
2 | import Vuex from 'vuex';
3 | import store from './store';
4 |
5 | Vue.use(Vuex);
6 |
7 | export default new Vuex.Store(store);
8 |
--------------------------------------------------------------------------------
/packages/garfish/__tests__/resources/vueIndex.js:
--------------------------------------------------------------------------------
1 | const dynamicScript = document.createElement('script');
2 | dynamicScript.src = 'dynamic.js';
3 | document.head.appendChild(dynamicScript);
4 |
--------------------------------------------------------------------------------
/packages/browser-vm/__tests__/resources/scripts/content-type-jsonp:
--------------------------------------------------------------------------------
1 |
2 | const testInfo = {
3 | key: 'contentTypeJsonp',
4 | value: true
5 | };
6 |
7 | window[testInfo.key] = testInfo.value;
8 |
--------------------------------------------------------------------------------
/packages/es-module/__tests__/case/resourceRedirect/m1.js:
--------------------------------------------------------------------------------
1 | import * as _ from 'https://unpkg.com/lodash-es';
2 | import lodash from 'https://unpkg.com/lodash-es';
3 |
4 | expect(_.default === lodash);
5 |
--------------------------------------------------------------------------------
/cypress/fixtures/example.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Using fixtures to represent data",
3 | "email": "hello@cypress.io",
4 | "body": "Fixtures are a great way to mock data for responses to routes"
5 | }
6 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | charset = utf-8
5 | indent_style = space
6 | indent_size = 2
7 | end_of_line = lf
8 | insert_final_newline = true
9 | trim_trailing_whitespace = true
10 |
11 |
--------------------------------------------------------------------------------
/packages/utils/src/logger.ts:
--------------------------------------------------------------------------------
1 | import createDebug from 'debug';
2 |
3 | const log = createDebug('garfish');
4 |
5 | export const coreLog = log.extend('core');
6 | export const routerLog = log.extend('router');
7 |
--------------------------------------------------------------------------------
/website/i18n/zh/docusaurus-theme-classic/footer.json:
--------------------------------------------------------------------------------
1 | {
2 | "copyright": {
3 | "message": "Copyright © 2021 ByteDance, Inc. Powered By Garfish Team",
4 | "description": "The footer copyright"
5 | }
6 | }
--------------------------------------------------------------------------------
/packages/garfish/tsup.config.ts:
--------------------------------------------------------------------------------
1 | import pkg from './package.json';
2 | import { baseTsup } from '../../tsup.config';
3 |
4 | export const tsup = {
5 | ...baseTsup(pkg),
6 | format: ['esm', 'cjs', 'iife'],
7 | };
8 |
--------------------------------------------------------------------------------
/dev/app-vue-2/src/shimsVue.d.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | declare module '*.vue' {
3 | import type { DefineComponent } from 'vue';
4 | const component: DefineComponent<{}, {}, any>;
5 | export default component;
6 | }
7 |
--------------------------------------------------------------------------------
/dev/app-vue-3/src/shimsVue.d.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | declare module '*.vue' {
3 | import type { DefineComponent } from 'vue';
4 | const component: DefineComponent<{}, {}, any>;
5 | export default component;
6 | }
7 |
--------------------------------------------------------------------------------
/dev/app-vue-vite/src/shimsVue.d.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | declare module '*.vue' {
3 | import type { DefineComponent } from 'vue';
4 | const component: DefineComponent<{}, {}, any>;
5 | export default component;
6 | }
7 |
--------------------------------------------------------------------------------
/dev/app-react-16/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | app react v17
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/dev/app-react-17/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | app react v17
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/dev/app-react-18/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | app react v17
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/dev/app-angular/src/app/topBar/topBar.component.css:
--------------------------------------------------------------------------------
1 | .link {
2 | display: inline-block;
3 | font-size: 16px;
4 | margin: 20px;
5 | /* color: white; */
6 | text-decoration: underline;
7 | }
8 | .active {
9 | color: darkred;
10 | }
11 |
--------------------------------------------------------------------------------
/packages/garfish/src/index.ts:
--------------------------------------------------------------------------------
1 | export type { interfaces } from '@garfish/core';
2 | export { default as Garfish } from '@garfish/core';
3 | export { GarfishInstance as default } from './instance';
4 | export { defineCustomElements } from './customElement';
5 |
--------------------------------------------------------------------------------
/dev/app-react-17/src/components/PageNotFound.tsx:
--------------------------------------------------------------------------------
1 | import { Result } from '@arco-design/web-react';
2 |
3 | const PageNotFound = () => {
4 | return ;
5 | };
6 |
7 | export default PageNotFound;
8 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/config.yml:
--------------------------------------------------------------------------------
1 | blank_issues_enabled: false
2 | contact_links:
3 | - name: Questions & Discussions
4 | url: https://github.com/modern-js-dev/garfish/discussions
5 | about: Use GitHub discussions for message-board style questions and discussions.
6 |
--------------------------------------------------------------------------------
/dev/app-angular/src/app/topBar/topBar.component.ts:
--------------------------------------------------------------------------------
1 | import { Component } from '@angular/core';
2 |
3 | @Component({
4 | selector: 'app-topBar',
5 | templateUrl: './topBar.component.html',
6 | styleUrls: ['./topBar.component.css'],
7 | })
8 | export class TopBarComponent {}
9 |
--------------------------------------------------------------------------------
/packages/browser-vm/__tests__/resources/scripts/event-task.js:
--------------------------------------------------------------------------------
1 | setTimeout(() => {
2 | window.execOrder.push('macro task');
3 | });
4 |
5 | Promise.resolve().then(() => {
6 | window.execOrder.push('micro task');
7 | });
8 |
9 | window.execOrder.push('normal task');
10 |
--------------------------------------------------------------------------------
/dev/app-react-16/src/PageNotFound.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Result } from '@arco-design/web-react';
3 |
4 | const PageNotFound = () => {
5 | return ;
6 | };
7 |
8 | export default PageNotFound;
9 |
--------------------------------------------------------------------------------
/dev/app-react-18/src/PageNotFound.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Result } from '@arco-design/web-react';
3 |
4 | const PageNotFound = () => {
5 | return ;
6 | };
7 |
8 | export default PageNotFound;
9 |
--------------------------------------------------------------------------------
/packages/hooks/src/index.ts:
--------------------------------------------------------------------------------
1 | export { PluginSystem } from './pluginSystem';
2 | export { SyncHook } from './syncHook';
3 | export { AsyncHook } from './asyncHook';
4 | export { SyncWaterfallHook } from './syncWaterfallHook';
5 | export { AsyncWaterfallHook } from './asyncWaterfallHooks';
6 |
--------------------------------------------------------------------------------
/packages/core/__tests__/__snapshots__/preloadPlugin.spec.ts.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`Core: preload plugin disablePreloadApp is false use setRanking 1`] = `"[{\\"appName\\":\\"vue-app\\",\\"count\\":2},{\\"appName\\":\\"react-app\\",\\"count\\":1}]"`;
4 |
--------------------------------------------------------------------------------
/dev/app-main/src/components/PageNotFound/index.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Result } from '@arco-design/web-react';
3 |
4 | const PageNotFound = () => {
5 | return ;
6 | };
7 |
8 | export default PageNotFound;
9 |
--------------------------------------------------------------------------------
/dev/app-angular/src/app/dashboard/dashboard.component.ts:
--------------------------------------------------------------------------------
1 | import { Component } from '@angular/core';
2 |
3 | @Component({
4 | selector: 'app-product-detail',
5 | templateUrl: './dashboard.component.html',
6 | styleUrls: ['./dashboard.component.css'],
7 | })
8 | export class DashboardComponent {}
9 |
--------------------------------------------------------------------------------
/website/src/components/sumarryImg/index.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 |
4 | export function summaryImg (url) {
5 | return (
6 |
7 |
8 |
9 |
10 |
11 | )
12 | }
13 |
--------------------------------------------------------------------------------
/website/plugin/slardar/index.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 |
3 | module.exports = function pluginSlardar(context, options) {
4 | return {
5 | name: 'plugin-slardar',
6 | getClientModules() {
7 | return [path.resolve(__dirname, 'initSlardar.js')];
8 | },
9 | };
10 | };
11 |
--------------------------------------------------------------------------------
/dev/app-angular/src/app/pageNotFound/pageNotFound.component.ts:
--------------------------------------------------------------------------------
1 | import { Component } from '@angular/core';
2 |
3 | @Component({
4 | selector: 'app-pageNotFound',
5 | templateUrl: './pageNotFound.component.html',
6 | styleUrls: ['./pageNotFound.component.css'],
7 | })
8 | export class PageNotFoundComponent {}
9 |
--------------------------------------------------------------------------------
/packages/es-module/__tests__/case/importMeta/m1.js:
--------------------------------------------------------------------------------
1 | expect(Object.getPrototypeOf(import.meta)).toBe(null);
2 |
3 | expect(Object.getOwnPropertyDescriptor(import.meta, 'url')).toEqual({
4 | writable: true,
5 | enumerable: true,
6 | configurable: true,
7 | value: 'http://localhost/case/importMeta/m1.js',
8 | });
9 |
--------------------------------------------------------------------------------
/packages/router/README.md:
--------------------------------------------------------------------------------
1 | # `@garfish/router`
2 |
3 | [](https://www.npmjs.com/package/@garfish/router)
4 |
5 | ## Usage
6 |
7 | ```js
8 | import router from '@garfish/router';
9 |
10 | // TODO: DEMONSTRATE API
11 | ```
12 |
--------------------------------------------------------------------------------
/packages/utils/src/index.ts:
--------------------------------------------------------------------------------
1 | export * from './utils';
2 | export * from './queue';
3 | export * from './sentry';
4 | export * from './domApis';
5 | export * from './garfish';
6 | export * from './mimeType';
7 | export * from './container';
8 | export * from './templateParse';
9 | export * from './logger';
10 |
--------------------------------------------------------------------------------
/packages/core/src/plugins/lifecycle.ts:
--------------------------------------------------------------------------------
1 | import { interfaces } from '../interface';
2 |
3 | export function GarfishOptionsLife(options, name: string) {
4 | return function (): interfaces.Plugin {
5 | return {
6 | name,
7 | version: __VERSION__,
8 | ...options,
9 | };
10 | };
11 | }
12 |
--------------------------------------------------------------------------------
/packages/core/__tests__/resources/reactApp.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | vue sub app
5 |
6 |
7 |
8 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/packages/utils/README.md:
--------------------------------------------------------------------------------
1 | # `@garfish/utils`
2 |
3 | [](https://www.npmjs.com/package/@garfish/utils)
4 |
5 | ## Usage
6 |
7 | ```js
8 | import { isObject } from '@garfish/utils';
9 |
10 | console.log(isObject({})); // true
11 | ```
12 |
--------------------------------------------------------------------------------
/dev/app-angular/src/app/topBar/topBar.component.html:
--------------------------------------------------------------------------------
1 | home
2 | dashboard
3 | list
4 |
--------------------------------------------------------------------------------
/packages/es-module/__tests__/case/executionOrder/m1.js:
--------------------------------------------------------------------------------
1 | expect(globalThis.orderIndex).toBe(2);
2 | globalThis.orderIndex++;
3 |
4 | import './m2.js';
5 |
6 | expect(globalThis.orderIndex).toBe(3);
7 | globalThis.orderIndex++;
8 |
9 | import './m3.js';
10 |
11 | expect(globalThis.orderIndex).toBe(4);
12 | globalThis.orderIndex++;
13 |
--------------------------------------------------------------------------------
/babel.config.js:
--------------------------------------------------------------------------------
1 |
2 | module.exports = {
3 | presets: [
4 | [
5 | '@babel/preset-env',
6 | {
7 | useBuiltIns: 'entry',
8 | targets: ['last 2 versions', 'ie >= 9'],
9 | modules: 'commonjs',
10 | },
11 | ],
12 | ],
13 | plugins: ['@babel/plugin-transform-regenerator'],
14 | };
15 |
16 |
--------------------------------------------------------------------------------
/dev/app-react-18/src/ErrorBoundary.tsx:
--------------------------------------------------------------------------------
1 | import { Result } from '@arco-design/web-react';
2 |
3 | const Error = () => {
4 | return (
5 |
10 | );
11 | };
12 |
13 | export default Error;
14 |
--------------------------------------------------------------------------------
/dev/app-vue-3/src/components/HelloGarfish.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
Thank you for the vue3 applications use garfish.
4 |

5 |
6 |
7 |
8 |
13 |
--------------------------------------------------------------------------------
/dev/app-vue-2/src/components/HelloGarfish.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
Thank you for the vue2 applications use garfish
4 |

5 |
6 |
7 |
8 |
13 |
--------------------------------------------------------------------------------
/packages/garfish/index.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 | ///
3 | ///
4 | export * from './dist/index';
5 | import defaultInstance from './dist/index';
6 |
7 | export { default as Garfish } from '@garfish/core';
8 | export default defaultInstance;
9 |
--------------------------------------------------------------------------------
/dev/app-react-17/src/components/ErrorBoundary.tsx:
--------------------------------------------------------------------------------
1 | import { Result } from '@arco-design/web-react';
2 |
3 | const Error = () => {
4 | return (
5 |
10 | );
11 | };
12 |
13 | export default Error;
14 |
--------------------------------------------------------------------------------
/packages/garfish/__tests__/__snapshots__/run.spec.ts.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`Core: run methods auto render and destroy vue app 1`] = `
4 | Array [
5 | "http://localhost/resources/vueIndex.js",
6 | "./resources/vueApp.html",
7 | undefined,
8 | "http://localhost/resources/dynamic.js",
9 | ]
10 | `;
11 |
--------------------------------------------------------------------------------
/dev/app-angular/src/app/home/home.component.ts:
--------------------------------------------------------------------------------
1 | import { Component } from '@angular/core';
2 |
3 | @Component({
4 | selector: 'app-home',
5 | templateUrl: './home.component.html',
6 | styleUrls: ['./home.component.css'],
7 | })
8 | export class HomeComponent {
9 | share() {
10 | window.alert('The product has been shared!');
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/scripts/utils.js:
--------------------------------------------------------------------------------
1 | const execa = require('execa');
2 | const chalk = require('chalk');
3 |
4 | const step = (msg) => {
5 | console.log(chalk.cyan(msg));
6 | };
7 |
8 | const run = async (bin, args, opts = {}) => {
9 | return await execa(bin, args, { stdio: 'inherit', ...opts });
10 | };
11 |
12 | module.exports = {
13 | run,
14 | step,
15 | };
16 |
--------------------------------------------------------------------------------
/dev/app-react-17/src/components/detail/index.less:
--------------------------------------------------------------------------------
1 | @import '../../less/variable.less';
2 |
3 | .@{prefix}-descriptions-title,
4 | .@{prefix}-descriptions-item-value {
5 | color: var(--color-text-4);
6 | }
7 | .@{prefix}-descriptions-title{
8 | text-align: left;
9 | }
10 | .@{prefix}-breadcrumb-item:last-child {
11 | color: var(--color-text-4);
12 | }
13 |
--------------------------------------------------------------------------------
/packages/browser-snapshot/README.md:
--------------------------------------------------------------------------------
1 | # `@garfish/browser-snapshot`
2 |
3 | [](https://www.npmjs.com/package/@garfish/browser-snapshot)
4 |
5 | ## Usage
6 |
7 | ```js
8 | import spSandbox from '@garfish/browser-snapshot';
9 |
10 | // TODO: DEMONSTRATE API
11 | ```
12 |
--------------------------------------------------------------------------------
/dev/app-angular/src/app/app.component.ts:
--------------------------------------------------------------------------------
1 | import { Injectable } from '@angular/core';
2 | import { Component } from '@angular/core';
3 |
4 | @Component({
5 | selector: 'app-root',
6 | templateUrl: './app.component.html',
7 | styleUrls: ['./app.component.css'],
8 | })
9 | @Injectable({
10 | providedIn: 'root',
11 | })
12 | export class AppComponent {}
13 |
--------------------------------------------------------------------------------
/dev/app-esm/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@garfish-dev/esm",
3 | "private": true,
4 | "scripts": {
5 | "start": "http-server ./src --cors -p 8099",
6 | "build": "cp -r src/. dist"
7 | },
8 | "publishConfig": {
9 | "registry": "https://registry.npmjs.org"
10 | },
11 | "devDependencies": {
12 | "http-server": "^14.1.0"
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/packages/es-module/__tests__/case/dynamicImport/m1.js:
--------------------------------------------------------------------------------
1 | import * as m2 from './m2.js';
2 | import arr, { name } from './m2.js';
3 |
4 | import('./m2.js').then((module) => {
5 | expect(module === m2).toBe(true);
6 | expect(module.default === arr).toBe(true);
7 | expect(module.name === name).toBe(true);
8 | expect(Object.keys(module).length).toBe(2);
9 | });
10 |
--------------------------------------------------------------------------------
/dev/app-angular/.editorconfig:
--------------------------------------------------------------------------------
1 | # Editor configuration, see https://editorconfig.org
2 | root = true
3 |
4 | [*]
5 | charset = utf-8
6 | indent_style = space
7 | indent_size = 2
8 | insert_final_newline = true
9 | trim_trailing_whitespace = true
10 |
11 | [*.ts]
12 | quote_type = single
13 |
14 | [*.md]
15 | max_line_length = off
16 | trim_trailing_whitespace = false
17 |
--------------------------------------------------------------------------------
/dev/app-react-16/src/ErrorBoundary.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Result } from '@arco-design/web-react';
3 |
4 | const Error = () => {
5 | return (
6 |
11 | );
12 | };
13 |
14 | export default Error;
15 |
--------------------------------------------------------------------------------
/packages/es-module/__tests__/case/circularReference/m2.js:
--------------------------------------------------------------------------------
1 | import { name } from './m1.js';
2 | import * as m1 from './m1.js';
3 |
4 | export const _name = 'm2';
5 |
6 | expect(() => name).toThrowError(/.?name.?/g);
7 | expect(() => m1.name).toThrowError(/.?name.?/g);
8 |
9 | setTimeout(() => {
10 | expect(name).toBe('m1');
11 | expect(m1.name).toBe('m1');
12 | });
13 |
--------------------------------------------------------------------------------
/packages/utils/src/garfish.ts:
--------------------------------------------------------------------------------
1 | export const __LOADER_FLAG__ = Symbol.for('__LOADER_FLAG__');
2 | export const __GARFISH_FLAG__ = Symbol.for('__GARFISH_FLAG__');
3 | export const __MockHtml__ = '__garfishmockhtml__';
4 | export const __MockBody__ = '__garfishmockbody__';
5 | export const __MockHead__ = '__garfishmockhead__';
6 | export const __REMOVE_NODE__ = '__garfishremovenode__';
7 |
--------------------------------------------------------------------------------
/website/.gitignore:
--------------------------------------------------------------------------------
1 | # Dependencies
2 | /node_modules
3 |
4 | # Production
5 | /build
6 | /output
7 | /output_resource
8 |
9 | # Generated files
10 | .docusaurus
11 | .cache-loader
12 |
13 | # Misc
14 | .DS_Store
15 | .env.local
16 | .env.development.local
17 | .env.test.local
18 | .env.production.local
19 |
20 | npm-debug.log*
21 | yarn-debug.log*
22 | yarn-error.log*
23 |
--------------------------------------------------------------------------------
/dev/app-angular/src/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Angular
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/dev/app-angular/e2e/tsconfig.json:
--------------------------------------------------------------------------------
1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */
2 | {
3 | "extends": "../tsconfig.json",
4 | "compilerOptions": {
5 | "outDir": "../out-tsc/e2e",
6 | "module": "commonjs",
7 | "target": "es2018",
8 | "types": [
9 | "jasmine",
10 | "jasminewd2",
11 | "node"
12 | ]
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/dev/app-angular/tsconfig.app.json:
--------------------------------------------------------------------------------
1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */
2 | {
3 | "extends": "./tsconfig.json",
4 | "compilerOptions": {
5 | "outDir": "./out-tsc/app",
6 | "types": []
7 | },
8 | "files": [
9 | "src/main.ts",
10 | "src/polyfills.ts"
11 | ],
12 | "include": [
13 | "src/**/*.d.ts"
14 | ]
15 | }
16 |
--------------------------------------------------------------------------------
/website/i18n/en/docusaurus-plugin-content-docs/current/community/discuss.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Garfish community
3 | slug: /community/discuss
4 | order: 1
5 | ---
6 |
7 | ### Github Discussions
8 |
9 | [Garfish Discussions](https://github.com/bytedance/garfish/discussions)
10 |
11 |
12 |
--------------------------------------------------------------------------------
/website/src/components/config/_protectVariable.mdx:
--------------------------------------------------------------------------------
1 | import Highlight from '@site/src/components/Highlight';
2 |
3 | - Type: string[]
4 | - 在开启沙箱的情况下,提供使得 window 上的某些变量处于受保护状态的能力:这些值的读写不会受到沙箱隔离机制的影响,所有应用均可读取到,可选;
5 | - 若希望在应用间共享 window 上的某些值,可将该值放置在数组中;
6 | - 该属性与 [setGlobalValue](/api/setGlobalObject) 功能相同,推荐使用 `protectVariable` 属性,通过 `protectVariable` 可以明确的感知哪些值可能在应用间相互影响;
7 |
--------------------------------------------------------------------------------
/dev/app-angular/e2e/src/app.po.ts:
--------------------------------------------------------------------------------
1 | import { browser, by, element } from 'protractor';
2 |
3 | export class AppPage {
4 | navigateTo(): Promise {
5 | return browser.get(browser.baseUrl) as Promise;
6 | }
7 |
8 | getTitleText(): Promise {
9 | return element(
10 | by.css('app-root .content span'),
11 | ).getText() as Promise;
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/dev/app-main/typings.d.ts:
--------------------------------------------------------------------------------
1 | declare interface Window {
2 | Garfish: any;
3 | __GARFISH__: any;
4 | }
5 |
6 | declare module '*.css';
7 | declare module '*.less';
8 | declare module '*.png';
9 | declare module '*.svg' {
10 | export function ReactComponent(
11 | props: React.SVGProps,
12 | ): React.ReactElement;
13 | const url: string;
14 | export default url;
15 | }
16 |
--------------------------------------------------------------------------------
/dev/app-react-17/typings.d.ts:
--------------------------------------------------------------------------------
1 | declare interface Window {
2 | Garfish: any;
3 | __GARFISH__: any;
4 | }
5 |
6 | declare module '*.css';
7 | declare module '*.less';
8 | declare module '*.png';
9 | declare module '*.svg' {
10 | export function ReactComponent(
11 | props: React.SVGProps,
12 | ): React.ReactElement;
13 | const url: string;
14 | export default url;
15 | }
16 |
--------------------------------------------------------------------------------
/dev/app-react-18/typings.d.ts:
--------------------------------------------------------------------------------
1 | declare interface Window {
2 | Garfish: any;
3 | __GARFISH__: any;
4 | }
5 |
6 | declare module '*.css';
7 | declare module '*.less';
8 | declare module '*.png';
9 | declare module '*.svg' {
10 | export function ReactComponent(
11 | props: React.SVGProps,
12 | ): React.ReactElement;
13 | const url: string;
14 | export default url;
15 | }
16 |
--------------------------------------------------------------------------------
/dev/app-vue-3/src/components/alertError.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
18 |
--------------------------------------------------------------------------------
/dev/app-vue-vite/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Vite App
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/website/docs/api/clearEscapeEffect.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Garfish.clearEscapeEffect
3 | slug: /api/clearEscapeEffect
4 | order: 9
5 | ---
6 |
7 | 用来清除逃逸沙箱的变量。
8 |
9 | > 在微前端应用下,子应用将默认开启沙箱模式。在沙箱模式下,若发现有一些特殊的行为会逃逸沙箱系统,可以使用此方法来清除逃逸的变量;
10 |
11 | ## Type
12 | ```ts
13 | clearEscapeEffect: (key: string, value?: any) => void;
14 | ```
15 |
16 | ## 示例
17 |
18 | ```js
19 | Garfish.clearEscapeEffect('webpackJsonp');
20 | ```
21 |
--------------------------------------------------------------------------------
/website/src/components/Highlight/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | export default function Highlight({ children, color }) {
4 | return (
5 |
13 | {children}
14 |
15 | );
16 | }
17 |
--------------------------------------------------------------------------------
/dev/app-esm/src/index.js:
--------------------------------------------------------------------------------
1 | let div;
2 |
3 | export function render() {
4 | div = document.createElement('div');
5 | const span = document.createElement('span');
6 | span.innerText = 'esmApp content';
7 | div.id = 'esmAppContent';
8 | div.appendChild(span);
9 | document.body.appendChild(div);
10 | }
11 |
12 | export function destroy() {
13 | if (div) {
14 | document.body.removeChild(div);
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/dev/app-vue-2/src/components/alertError.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
18 |
--------------------------------------------------------------------------------
/scripts/e2e.js:
--------------------------------------------------------------------------------
1 | const { run, step } = require('./utils');
2 | const { runAllExample } = require('./runE2eProject');
3 |
4 | runAllExample().then(() => {
5 | // once here, all resources are available
6 | step('\n start e2e test...');
7 | const spawnInstance = run('pnpm', [
8 | process.env.TEST_ENV_OPEN ? 'cy:open' : 'cy:run',
9 | ]);
10 | spawnInstance.stdout?.on('data', (msg) => step(msg.toString()));
11 | });
12 |
--------------------------------------------------------------------------------
/packages/browser-snapshot/__tests__/__snapshots__/sandbox.spec.ts.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`test sandbox dom sandbox 1`] = `
4 | NodeList [
5 | ,
8 | ,
11 | ]
12 | `;
13 |
14 | exports[`test sandbox dom sandbox 2`] = `
15 | Object {
16 | "age": "23",
17 | "name": "wu",
18 | }
19 | `;
20 |
--------------------------------------------------------------------------------
/dev/app-angular/tsconfig.spec.json:
--------------------------------------------------------------------------------
1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */
2 | {
3 | "extends": "./tsconfig.json",
4 | "compilerOptions": {
5 | "outDir": "./out-tsc/spec",
6 | "types": [
7 | "jasmine"
8 | ]
9 | },
10 | "files": [
11 | "src/test.ts",
12 | "src/polyfills.ts"
13 | ],
14 | "include": [
15 | "src/**/*.spec.ts",
16 | "src/**/*.d.ts"
17 | ]
18 | }
19 |
--------------------------------------------------------------------------------
/dev/app-vue-vite/README.md:
--------------------------------------------------------------------------------
1 | # Vue 3 + Vite
2 |
3 | This template should help get you started developing with Vue 3 in Vite. The template uses Vue 3 `
19 |
20 |
30 |
--------------------------------------------------------------------------------
/dev/app-vue/src/components/HelloWorld.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
{{ msg }}
4 |
5 | Thank you for using Garfish
6 |
7 |
8 |
9 |
10 |
18 |
19 |
20 |
39 |
--------------------------------------------------------------------------------
/website/src/components/lifeCycle/_afterEval.mdx:
--------------------------------------------------------------------------------
1 | import Highlight from '@site/src/components/Highlight';
2 |
3 | - Type: (appInfo: AppInfo, code: string, env: Record, url: string, options) => void
4 | - 该 `hook` 的参数分别为:`appInfo` 信息、`code` 执行的代码、`env` 要注入的环境变量,`url` 应用访问地址、`options` 参数选项例如 `async` 是否异步执行、`noEntry` 是否是 `noEntry` 模式;
5 | - Kind: `sync`, `sequential`
6 | - Previous Hook: `beforeLoad`、`afterLoad`
7 | - Trigger:
8 |
9 | - 在实际执行代码后。`afterMount` 触发前触发;
10 | - 子应用 html 内的 script 和动态创建的脚本执行时都会触发该 hook
11 |
12 | - 示例
13 |
14 | ```ts
15 | Garfish.afterEval({
16 | ...,
17 | afterEval(appInfo) {
18 | console.log('子应用代码执行完成', appInfo.name);
19 | }
20 | })
21 | ```
22 |
--------------------------------------------------------------------------------
/packages/browser-vm/__tests__/modules/uiEvent.spec.ts:
--------------------------------------------------------------------------------
1 | import { MouseEventPatch } from '../../src/modules/uiEvent';
2 |
3 | /**
4 | * The logic of UIEvent is referenced from qiankun typography
5 | * https://github.com/umijs/qiankun/pull/593/files
6 | */
7 | test('patch UIEvent', async () => {
8 | const dispatchEventAction = jest.fn();
9 |
10 | const dom = document.createElement('a');
11 | dom.onclick = dispatchEventAction;
12 |
13 | const evt = new MouseEventPatch('click', {
14 | view: new Proxy(window, {}), // fakeWindow can't use to MouseEventPatch
15 | bubbles: true,
16 | cancelable: false,
17 | });
18 | dom.dispatchEvent(evt);
19 |
20 | expect(dispatchEventAction).toBeCalledTimes(1);
21 | });
22 |
--------------------------------------------------------------------------------
/dev/app-react-16/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [
3 | "@babel/preset-env",
4 | "@babel/preset-typescript",
5 | [
6 | "@babel/preset-react", {
7 | "runtime": "automatic"
8 | }
9 | ]
10 | ],
11 | "plugins": [
12 | "@babel/plugin-syntax-dynamic-import",
13 | [
14 | "@babel/plugin-transform-runtime",
15 | {
16 | "regenerator": true
17 | }
18 | ],
19 | [
20 | "@babel/plugin-proposal-decorators",
21 | {
22 | "legacy": true
23 | }
24 | ],
25 | "@babel/plugin-proposal-class-properties",
26 | [
27 | "@babel/plugin-transform-react-jsx",
28 | {
29 | "runtime": "automatic"
30 | }
31 | ]
32 | ]
33 | }
34 |
--------------------------------------------------------------------------------
/dev/app-react-17/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [
3 | "@babel/preset-env",
4 | "@babel/preset-typescript",
5 | [
6 | "@babel/preset-react", {
7 | "runtime": "automatic"
8 | }
9 | ]
10 | ],
11 | "plugins": [
12 | "@babel/plugin-syntax-dynamic-import",
13 | [
14 | "@babel/plugin-transform-runtime",
15 | {
16 | "regenerator": true
17 | }
18 | ],
19 | [
20 | "@babel/plugin-proposal-decorators",
21 | {
22 | "legacy": true
23 | }
24 | ],
25 | "@babel/plugin-proposal-class-properties",
26 | [
27 | "@babel/plugin-transform-react-jsx",
28 | {
29 | "runtime": "automatic"
30 | }
31 | ]
32 | ]
33 | }
34 |
--------------------------------------------------------------------------------
/dev/app-react-18/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [
3 | "@babel/preset-env",
4 | "@babel/preset-typescript",
5 | [
6 | "@babel/preset-react", {
7 | "runtime": "automatic"
8 | }
9 | ]
10 | ],
11 | "plugins": [
12 | "@babel/plugin-syntax-dynamic-import",
13 | [
14 | "@babel/plugin-transform-runtime",
15 | {
16 | "regenerator": true
17 | }
18 | ],
19 | [
20 | "@babel/plugin-proposal-decorators",
21 | {
22 | "legacy": true
23 | }
24 | ],
25 | "@babel/plugin-proposal-class-properties",
26 | [
27 | "@babel/plugin-transform-react-jsx",
28 | {
29 | "runtime": "automatic"
30 | }
31 | ]
32 | ]
33 | }
34 |
--------------------------------------------------------------------------------
/packages/browser-vm/src/modules/uiEvent.ts:
--------------------------------------------------------------------------------
1 | import { getType } from '@garfish/utils';
2 |
3 | // The logic of UIEvent is referenced from qiankun typography
4 | // https://github.com/umijs/qiankun/pull/593/files
5 | // TODO: fix normal mouse event instanceof MouseEvent === false
6 | export class MouseEventPatch extends MouseEvent {
7 | constructor(typeArg: string, mouseEventInit?: MouseEventInit) {
8 | if (mouseEventInit && getType(mouseEventInit.view) === 'window') {
9 | mouseEventInit.view = window;
10 | }
11 | super(typeArg, mouseEventInit);
12 | }
13 | }
14 |
15 | export function UiEventOverride() {
16 | return {
17 | override: {
18 | MouseEvent: MouseEventPatch as any,
19 | },
20 | };
21 | }
22 |
--------------------------------------------------------------------------------
/website/docs/api/setOptioins.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Garfish.setOptions
3 | slug: /api/setOptions
4 | order: 5
5 | ---
6 |
7 | 在 `Garfish.run` 调用前用于动态更新配置信息的API,参数与 [Garfish.run](/api/run) 保持一致。
8 | ## 设计初衷
9 | 在某些场景下,微前端应用的初始化参数信息在运行过程中可能会出现混乱不一致的情况,提供该 `API` 用于用户在复杂场景下设置全局微前端应用参数信息,此 API 作用于全局 Garfish 实例。
10 |
11 | :::info
12 | `Garfish.setOptions` 用于微前端应用启动前的参数变更。在触发了 `run` 方法后,不可以再通过 `setOptions` 更改应用配置。
13 | :::
14 |
15 | ## 示例
16 |
17 | ```js
18 | // 主应用 index.js
19 | import Garfish from 'garfish';
20 |
21 | Garfish.setOptions({
22 | basename: '/',
23 | domGetter: '#container',
24 | // xxx
25 | });
26 | ```
27 |
28 | ## 参数
29 |
30 | `Options`
31 |
32 | - 此 API 参数与 [Garfish.run](/api/run) 保持一致。 请参考 [Garfish.run](/api/run#参数);
33 |
--------------------------------------------------------------------------------
/dev/app-vue-2/public/remoteModule.js:
--------------------------------------------------------------------------------
1 | // const loadModule = require('loadModule');
2 | // console.log(loadModule);
3 |
4 | const components = {
5 | cmOne: {
6 | props: ['text'],
7 | data: () => ({
8 | name: 'chen',
9 | }),
10 | render(h) {
11 | return h('div', {}, [this.text, '---', this.name]);
12 | },
13 | },
14 |
15 | cmTwo: {
16 | props: ['text'],
17 | data: () => ({
18 | name: 'tao',
19 | }),
20 | render(h) {
21 | return h('div', {}, [this.text, '---', this.name]);
22 | },
23 | },
24 | };
25 |
26 | module.exports = new Promise((resolve) => {
27 | console.log('loading other modules.');
28 | setTimeout(() => {
29 | resolve(components);
30 | }, 100);
31 | });
32 |
--------------------------------------------------------------------------------
/dev/app-vue/public/remoteModule.js:
--------------------------------------------------------------------------------
1 | // const loadModule = require('loadModule');
2 | // console.log(loadModule);
3 |
4 | const components = {
5 | cmOne: {
6 | props: ['text'],
7 | data: () => ({
8 | name: 'chen',
9 | }),
10 | render(h) {
11 | return h('div', {}, [this.text, '---', this.name]);
12 | },
13 | },
14 |
15 | cmTwo: {
16 | props: ['text'],
17 | data: () => ({
18 | name: 'tao',
19 | }),
20 | render(h) {
21 | return h('div', {}, [this.text, '---', this.name]);
22 | },
23 | },
24 | };
25 |
26 | module.exports = new Promise((resolve) => {
27 | console.log('loading other modules.');
28 | setTimeout(() => {
29 | resolve(components);
30 | }, 100);
31 | });
32 |
--------------------------------------------------------------------------------
/packages/loader/src/managers/module.ts:
--------------------------------------------------------------------------------
1 | export class ModuleManager {
2 | public moduleCode: string;
3 | public url: string | null;
4 | public originUrl?: string;
5 | public alias: string | null;
6 |
7 | constructor(moduleCode: string, url?: string) {
8 | this.alias = null;
9 | this.url = url || null;
10 | this.moduleCode = moduleCode;
11 | }
12 |
13 | setAlias(name: string) {
14 | if (name && typeof name === 'string') {
15 | this.alias = name;
16 | }
17 | }
18 |
19 | clone() {
20 | // @ts-ignore
21 | const cloned = new this.constructor();
22 | cloned.url = this.url;
23 | cloned.alias = this.alias;
24 | cloned.moduleCode = this.moduleCode;
25 | return cloned;
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/dev/app-angular/tsconfig.json:
--------------------------------------------------------------------------------
1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */
2 | {
3 | "compileOnSave": false,
4 | "compilerOptions": {
5 | "baseUrl": "./",
6 | "outDir": "./dist/out-tsc",
7 | "typeRoots": ["./src/typings"],
8 | "sourceMap": true,
9 | "declaration": false,
10 | "downlevelIteration": true,
11 | "experimentalDecorators": true,
12 | "moduleResolution": "node",
13 | "importHelpers": true,
14 | "target": "es2015",
15 | "module": "esnext",
16 | "lib": [
17 | "es2018",
18 | "dom"
19 | ]
20 | },
21 | "angularCompilerOptions": {
22 | "enableI18nLegacyMessageIdFormat": false,
23 | "strictInjectionParameters": true,
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/packages/browser-vm/src/modules/mutationObserver.ts:
--------------------------------------------------------------------------------
1 | import { Sandbox } from '../sandbox';
2 |
3 | export function observerModule(_sandbox: Sandbox) {
4 | const observerSet = new Set();
5 |
6 | class ProxyMutationObserver extends MutationObserver {
7 | constructor(cb: MutationCallback) {
8 | super(cb);
9 | observerSet.add(this);
10 | }
11 | }
12 |
13 | const recover = () => {
14 | observerSet.forEach((observer) => {
15 | if (typeof observer.disconnect === 'function') observer.disconnect();
16 | });
17 | observerSet.clear();
18 | };
19 |
20 | return {
21 | recover,
22 | override: {
23 | MutationObserver: ProxyMutationObserver as Function,
24 | },
25 | };
26 | }
27 |
--------------------------------------------------------------------------------
/packages/hooks/src/asyncHook.ts:
--------------------------------------------------------------------------------
1 | import { ArgsType, SyncHook } from './syncHook';
2 |
3 | type CallbackReturnType = void | false | Promise;
4 |
5 | export class AsyncHook extends SyncHook {
6 | emit(...data: ArgsType): Promise {
7 | let result;
8 | const ls = Array.from(this.listeners);
9 | if (ls.length > 0) {
10 | let i = 0;
11 | const call = (prev?: any) => {
12 | if (prev === false) {
13 | return false; // Abort process
14 | } else if (i < ls.length) {
15 | return Promise.resolve(ls[i++].apply(null, data)).then(call);
16 | }
17 | };
18 | result = call();
19 | }
20 | return Promise.resolve(result);
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/dev/app-angular/src/environments/environment.ts:
--------------------------------------------------------------------------------
1 | // This file can be replaced during build by using the `fileReplacements` array.
2 | // `ng build --prod` replaces `environment.ts` with `environment.prod.ts`.
3 | // The list of file replacements can be found in `angular.json`.
4 |
5 | export const environment = {
6 | production: false,
7 | };
8 |
9 | /*
10 | * For easier debugging in development mode, you can import the following file
11 | * to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`.
12 | *
13 | * This import should be commented out in production mode because it will have a negative impact
14 | * on performance if an error is thrown.
15 | */
16 | // import 'zone.js/dist/zone-error'; // Included with Angular CLI.
17 |
--------------------------------------------------------------------------------
/cypress/support/index.js:
--------------------------------------------------------------------------------
1 | // ***********************************************************
2 | // This example support/index.js is processed and
3 | // loaded automatically before your test files.
4 | //
5 | // This is a great place to put global configuration and
6 | // behavior that modifies Cypress.
7 | //
8 | // You can change the location of this file or turn off
9 | // automatically serving support files with the
10 | // 'supportFile' configuration option.
11 | //
12 | // You can read more here:
13 | // https://on.cypress.io/configuration
14 | // ***********************************************************
15 |
16 | // Import commands.js using ES2015 syntax:
17 | import './commands';
18 |
19 | // Alternatively you can use CommonJS syntax:
20 | // require('./commands')
21 |
--------------------------------------------------------------------------------
/packages/es-module/__tests__/case/exportDeclaration/m1.js:
--------------------------------------------------------------------------------
1 | import dd, {
2 | name,
3 | a,
4 | b,
5 | c,
6 | d,
7 | aa,
8 | fn1,
9 | fn2,
10 | _fn3,
11 | cls,
12 | name1,
13 | bar,
14 | default as dd2,
15 | } from './m2.js';
16 |
17 | expect(name).toBe('m2');
18 | expect(dd.length).toBe(1);
19 | expect(dd[0]).toBe('default');
20 | expect(dd2 === dd).toBe(true);
21 | expect(a).toBe(1);
22 | expect(b).toBe(2);
23 | expect(c).toBe(3);
24 | expect(d).toBe(4);
25 | expect(aa).toBe(1);
26 | expect(fn1()).toBe('fn1');
27 | expect(fn2()).toBe('fn2');
28 | expect(_fn3()).toBe('fn3');
29 | expect(new cls().world()).toBe('cls.world');
30 | expect(name1).toBe('n1');
31 | expect(bar).toBe('n2');
32 |
33 | setTimeout(() => {
34 | expect(a).toBe('aa');
35 | });
36 |
--------------------------------------------------------------------------------
/website/i18n/zh/docusaurus-plugin-content-docs/current.json:
--------------------------------------------------------------------------------
1 | {
2 | "version.label": {
3 | "message": "Next",
4 | "description": "The label for version current"
5 | },
6 | "sidebar.guide.category.指南": {
7 | "message": "指南",
8 | "description": "The label for category 指南 in sidebar guide"
9 | },
10 | "sidebar.guide.category.快速开始": {
11 | "message": "快速开始",
12 | "description": "The label for category 快速开始 in sidebar guide"
13 | },
14 | "sidebar.guide.category.进阶功能": {
15 | "message": "进阶功能",
16 | "description": "The label for category 进阶功能 in sidebar guide"
17 | },
18 | "sidebar.api.category.Garfish methods": {
19 | "message": "Garfish methods",
20 | "description": "The label for category Garfish methods in sidebar api"
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/dev/app-angular/e2e/src/app.e2e-spec.ts:
--------------------------------------------------------------------------------
1 | import { AppPage } from './app.po';
2 | import { browser, logging } from 'protractor';
3 |
4 | describe('workspace-project App', () => {
5 | let page: AppPage;
6 |
7 | beforeEach(() => {
8 | page = new AppPage();
9 | });
10 |
11 | it('should display welcome message', () => {
12 | page.navigateTo();
13 | expect(page.getTitleText()).toEqual('angular app is running!');
14 | });
15 |
16 | afterEach(async () => {
17 | // Assert that there are no errors emitted from the browser
18 | const logs = await browser.manage().logs().get(logging.Type.BROWSER);
19 | expect(logs).not.toContain(
20 | jasmine.objectContaining({
21 | level: logging.Level.SEVERE,
22 | } as logging.Entry),
23 | );
24 | });
25 | });
26 |
--------------------------------------------------------------------------------
/website/src/components/lifeCycle/_beforeMount.mdx:
--------------------------------------------------------------------------------
1 | import Highlight from '@site/src/components/Highlight';
2 |
3 | - Type: (appInfo: AppInfo, appInstance: interfaces.App, cacheMode: boolean) => void
4 | - 该 `hook` 的参数分别为:`appInfo` 信息、`appInstance` 应用实例、是否为 `缓存模式` 渲染和销毁
5 | - Kind: `sync`, `sequential`
6 | - Previous Hook: `beforeEval`、`afterEval`
7 | - Trigger:
8 |
9 | - 此时子应用资源准备完成,运行时环境初始化完成,准备开始渲染子应用 DOM 树;
10 | - 在调用 `app.mount` 或 `app.show` 触发该 `hook`,用户除了手动调用这两个方法外,`Garfish Router` 托管模式还会自动触发
11 | - 在使用 `app.mount` 渲染应用是 `cacheMode` 为 `false`;
12 | - 在使用 `app.show` 渲染应用是 `cacheMode` 为 `true`;
13 |
14 | - 示例
15 |
16 | ```ts
17 | Garfish.run({
18 | ...,
19 | beforeMount(appInfo) {
20 | console.log('子应用开始渲染', appInfo.name);
21 | }
22 | })
23 | ```
24 |
--------------------------------------------------------------------------------
/dev/app-esm/src/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | esm-app
8 |
13 |
14 |
15 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/dev/app-vue-vite/src/App.vue:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
10 |
![Vue logo]()
11 |
12 |
13 |
14 |
15 |
27 |
--------------------------------------------------------------------------------
/packages/remote-module/src/apis/esModule.ts:
--------------------------------------------------------------------------------
1 | import { isObject, isPromise } from '@garfish/utils';
2 |
3 | type ESModuleResult = {
4 | default: T;
5 | __esModule: true;
6 | };
7 |
8 | // prettier-ignore
9 | export function esModule>(obj: T): Promise ? P : T>>;
10 | export function esModule>(obj: T): T;
11 | export function esModule(obj: T): ESModuleResult;
12 |
13 | export function esModule(obj: any) {
14 | if (isObject(obj) && obj.__esModule === true) {
15 | return obj;
16 | } else if (isPromise(obj)) {
17 | return obj.then(esModule);
18 | } else {
19 | const esm = { default: obj };
20 | Object.defineProperty(esm, '__esModule', { value: true });
21 | return esm;
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/packages/remote-module/src/index.ts:
--------------------------------------------------------------------------------
1 | import { hooks } from './hooks';
2 | import { loader, cacheModules } from './common';
3 | import { preload } from './apis/preload';
4 | import { esModule } from './apis/esModule';
5 | import { loadModule } from './apis/loadModule';
6 | import { loadModuleSync } from './apis/loadModuleSync';
7 | import { setModuleConfig } from './apis/setModuleConfig';
8 |
9 | // Remote module loader uses singleton mode
10 | const Apis = {
11 | preload,
12 | esModule,
13 | loadModule,
14 | loadModuleSync,
15 | setModuleConfig,
16 | hooks,
17 | loader,
18 | cacheModules,
19 | };
20 |
21 | export {
22 | preload,
23 | esModule,
24 | loadModule,
25 | loadModuleSync,
26 | setModuleConfig,
27 | hooks,
28 | loader,
29 | cacheModules,
30 | Apis as default,
31 | };
32 |
--------------------------------------------------------------------------------
/website/i18n/en/docusaurus-plugin-content-docs/current.json:
--------------------------------------------------------------------------------
1 | {
2 | "version.label": {
3 | "message": "Next",
4 | "description": "The label for version current"
5 | },
6 | "sidebar.guide.category.指南": {
7 | "message": "guide",
8 | "description": "The label for category 指南 in sidebar guide"
9 | },
10 | "sidebar.guide.category.快速开始": {
11 | "message": "Quick start",
12 | "description": "The label for category 快速开始 in sidebar guide"
13 | },
14 | "sidebar.guide.category.进阶功能": {
15 | "message": "Advanced features",
16 | "description": "The label for category 进阶功能 in sidebar guide"
17 | },
18 | "sidebar.api.category.Garfish methods": {
19 | "message": "Garfish methods",
20 | "description": "The label for category Garfish methods in sidebar api"
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/website/src/components/lifeCycle/_afterMount.mdx:
--------------------------------------------------------------------------------
1 | import Highlight from '@site/src/components/Highlight';
2 |
3 | - Type: (appInfo: AppInfo, appInstance: interfaces.App, cacheMode: boolean) => void
4 | - 该 `hook` 的参数分别为:`appInfo` 信息、`appInstance` 应用实例、是否为 `缓存模式` 渲染和销毁
5 | - Kind: `sync`, `sequential`
6 | - Previous Hook: `beforeLoad`、`afterLoad`、`beforeMount`
7 | - Trigger:
8 |
9 | - 此时子应用 DOM 树已渲染完成,garfish 实例 `activeApps` 中已添加当前子应用 app 实例;
10 | - 在挂载过程中,会调用应用生命周期中的 [`render` 函数](/guide/start#2导出-provider-函数),用户可在挂载前定义相关操作;
11 | - 若挂载过程中出现异常,会触发 [errorMountApp](/api/run#errormountapp),同时会清除已创建的 app 渲染容器 appContainer
12 |
13 | - 示例
14 |
15 | ```ts
16 | Garfish.run({
17 | ...,
18 | afterMount(appInfo) {
19 | console.log('子应用渲染结束', appInfo.name);
20 | }
21 | })
22 | ```
23 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "baseUrl": ".",
4 | "rootDir": ".",
5 | "outDir": "dist",
6 | "module": "ESNext",
7 | "target": "es2016",
8 | "resolveJsonModule": true,
9 | "lib": ["ES2018","dom"],
10 | "moduleResolution": "node",
11 | "allowJs": true,
12 | "sourceMap": true,
13 | "declaration": true,
14 | "noImplicitThis": true,
15 | "esModuleInterop": true,
16 | "emitDecoratorMetadata": true,
17 | "strictNullChecks": true,
18 | "experimentalDecorators": true,
19 | "skipLibCheck": true,
20 | "paths": {
21 | "@garfish/*": ["packages/*/src"]
22 | },
23 | "types": ["jasmine", "jest"]
24 | },
25 | "include": [
26 | "packages/*/src",
27 | "packages/*/__tests__",
28 | "packages/global.d.ts"
29 | ]
30 | }
31 |
--------------------------------------------------------------------------------
/dev/app-vue/src/store/store.js:
--------------------------------------------------------------------------------
1 | export default {
2 | state: {
3 | id: 1,
4 | todos: [{ id: 1, text: 'write a vue mudole demo', done: false }],
5 | },
6 |
7 | mutations: {
8 | done(state, id) {
9 | // state.todos.forEach((item) => item.id === id && (item.done = true));
10 | this.state.todo = this.state.todo.filter((item) => item.id !== id);
11 | },
12 | add(state, item) {
13 | state.id += 1;
14 | item.id = state.id;
15 | state.todos.push(item);
16 | },
17 | },
18 |
19 | actions: {
20 | done(context, id) {
21 | context.commit('done', id);
22 | },
23 | add(context, item) {
24 | context.commit('add', item);
25 | },
26 | },
27 |
28 | getters: {
29 | doneTodos: (state) => state.todos.filter((todo) => todo.done),
30 | },
31 | };
32 |
--------------------------------------------------------------------------------
/website/i18n/en/docusaurus-plugin-content-docs/current/issues/multipleApp.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Multiple Garfish Instances
3 | slug: /issues/multipleApp
4 | order: 2
5 | ---
6 |
7 | ## Non-Nested Scenarios
8 |
9 | - In non-nested scenarios, sub-applications should not introduce Garfish packages in the installation and import them for use.
10 | - If you want to use the Garfish package in a micro front-end scenario, you can use the interface via `window.Garfish` when you are in the micro front-end environment.
11 |
12 | ```js
13 | if (window.__GARFISH__) {
14 | window.Garfish.xx;
15 | }
16 | ```
17 |
18 | ## Nested scenarios
19 |
20 | - Garfish is currently designed internally to support nested scenarios, so if the business has a claim on this piece you can use it to help us advance our capabilities in nested scenarios together.
21 |
--------------------------------------------------------------------------------
/packages/core/__tests__/resources/vueApp.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | vue sub app
5 |
6 |
7 |
8 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/website/src/components/lifeCycle/_beforeEval.mdx:
--------------------------------------------------------------------------------
1 | import Highlight from '@site/src/components/Highlight';
2 |
3 | - Type: (appInfo: AppInfo, code: string, env: Record, url: string, options) => void
4 | - 该 `hook` 的参数分别为:`appInfo` 信息、`code` 执行的代码、`env` 要注入的环境变量,`url` 代码的资源地址、`options` 参数选项(例如 `async` 是否异步执行、`noEntry` 是否是 `noEntry` 模式);
5 | - Kind: `sync`, `sequential`
6 | - Previous Hook: `beforeMount`
7 | - Trigger:
8 |
9 | - 在子应用挂载过程中、实际执行代码前触发该 hook;
10 | - 应用 html 内的 script 和动态创建的脚本执行时都会触发该 hook
11 | - 此时 DOM 树已添加至文档流中,子应用代码准备执行;
12 | - 若代码执行过程中抛出异常,则将触发 [errorMountApp](/api/run#errormountapp),否则触发 [beforeEval](/api/run#afterEval)
13 |
14 | - 示例
15 |
16 | ```ts
17 | Garfish.beforeEval({
18 | ...,
19 | beforeEval(appInfo) {
20 | console.log('子应用代码开始执行', appInfo.name);
21 | }
22 | })
23 | ```
24 |
--------------------------------------------------------------------------------
/packages/browser-vm/src/dynamicNode/processParams.ts:
--------------------------------------------------------------------------------
1 | import { handlerParams } from '../utils';
2 |
3 | export function injectHandlerParams() {
4 | if (window.MutationObserver) {
5 | const rawObserver = window.MutationObserver.prototype.observe;
6 | MutationObserver.prototype.observe = function () {
7 | return rawObserver.apply(this, handlerParams(arguments));
8 | };
9 | }
10 |
11 | // in iframe not modify activeElement
12 | const desc = Object.getOwnPropertyDescriptor(
13 | window.Document.prototype,
14 | 'activeElement',
15 | );
16 | const rawActiveEl = desc && desc.get;
17 | if (rawActiveEl) {
18 | Object.defineProperty(window.Document.prototype, 'activeElement', {
19 | get(...args) {
20 | return rawActiveEl.apply(handlerParams([this])[0], handlerParams(args));
21 | },
22 | });
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/packages/core/__tests__/resources/vue3App.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | vue3 sub app
5 |
6 |
7 |
8 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/dev/app-angular/src/main.ts:
--------------------------------------------------------------------------------
1 | import { enableProdMode, NgModuleRef } from '@angular/core';
2 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
3 | import { AppModule } from './app/app.module';
4 | import { environment } from './environments/environment';
5 |
6 | if (environment.production) {
7 | enableProdMode();
8 | }
9 |
10 | let app: void | NgModuleRef;
11 |
12 | async function render() {
13 | await platformBrowserDynamic()
14 | .bootstrapModule(AppModule)
15 | .catch((err) => console.error(err));
16 | }
17 |
18 | if (!(window as any).__GARFISH__) {
19 | render();
20 | }
21 |
22 | export const provider = () => {
23 | return {
24 | render,
25 | destroy({ dom }) {
26 | const root = dom
27 | ? dom.querySelector('#root')
28 | : document.querySelector('#root');
29 | },
30 | };
31 | };
32 |
--------------------------------------------------------------------------------
/packages/garfish/__tests__/resources/reactApp.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | react sub app
5 |
6 |
7 |
8 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/dev/app-angular/src/test.ts:
--------------------------------------------------------------------------------
1 | // This file is required by karma.conf.js and loads recursively all the .spec and framework files
2 |
3 | import 'zone.js/dist/zone-testing';
4 | import { getTestBed } from '@angular/core/testing';
5 | import {
6 | BrowserDynamicTestingModule,
7 | platformBrowserDynamicTesting,
8 | } from '@angular/platform-browser-dynamic/testing';
9 |
10 | declare const require: {
11 | context(
12 | path: string,
13 | deep?: boolean,
14 | filter?: RegExp,
15 | ): {
16 | keys(): string[];
17 | (id: string): T;
18 | };
19 | };
20 |
21 | // First, initialize the Angular testing environment.
22 | getTestBed().initTestEnvironment(
23 | BrowserDynamicTestingModule,
24 | platformBrowserDynamicTesting(),
25 | );
26 | // Then we find all the tests.
27 | const context = require.context('./', true, /\.spec\.ts$/);
28 | // And load the modules.
29 | context.keys().map(context);
30 |
--------------------------------------------------------------------------------
/dev/app-main/src/store.ts:
--------------------------------------------------------------------------------
1 | import { observable, computed, action, makeAutoObservable } from 'mobx';
2 | class Store {
3 | @observable price = 2;
4 | @observable counter = 1;
5 | @observable activeApp = '';
6 | @observable apps = [];
7 | @observable isMounted = undefined;
8 |
9 | constructor() {
10 | makeAutoObservable(this);
11 | }
12 |
13 | @computed get total() {
14 | return this.price * this.counter;
15 | }
16 |
17 | @action.bound
18 | increment() {
19 | this.counter++;
20 | }
21 |
22 | @action.bound
23 | decrement() {
24 | this.counter--;
25 | }
26 |
27 | @action
28 | setActiveApp(name) {
29 | this.activeApp = name;
30 | }
31 | @action
32 | setApps(apps) {
33 | this.apps = apps;
34 | }
35 | @action
36 | setIsMounted(isMounted) {
37 | this.isMounted = isMounted;
38 | }
39 | }
40 |
41 | export default Store;
42 | export const store = new Store();
43 |
--------------------------------------------------------------------------------
/website/docs/api/getGlobal.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Garfish.getGlobalObject
3 | slug: /api/getGlobalObject
4 | order: 7
5 | ---
6 | import Highlight from '@site/src/components/Highlight';
7 |
8 | 用于子应用获取真实 window 的值。
9 |
10 | > 在微前端应用下,子应用将默认开启沙箱模式。在沙箱模式下,子应用中全局变量为被 proxy 的 'fakeWindow',而全局变量(真实 window)默认会被隔离。若子应用需求获取真实 window 的值,可以通过此方法获取。
11 |
12 |
13 | :::tip
14 | 1. 一般情况下我们不建议直接通过此 API 获取真实 window,这样建议的原因是:
15 | - 使用此 API 后子应用产生了一个无法独立运行的逻辑,导致子应用失去独立运行的能力;
16 | - 由于环境变量的修改并不是单向数据流,造成主应用无法感知哪些子应用会去修改 window 上的哪些变量,可能造成数据管理的混乱;
17 |
18 | 2. 若需要获取真实 window 上的环境变量,可通过 [`protectVariable`](/api/run#protectvariable) 属性,将需要共享的属性放入列表中即可通过子应用的全局变量获取,这样主应用能感知到哪些值是会被修改的,哪些值是不会被修改的,能在一定程度上控制 `window` 变量的修改;
19 | :::
20 |
21 | ## Type
22 | ```ts
23 | getGlobalObject: () => Window & typeof globalThis;
24 | ```
25 | ## 示例
26 |
27 | ```js
28 | import Garfish from 'garfish';
29 |
30 | const nativeWindow = Garfish.getGlobalObject();
31 | ```
32 |
--------------------------------------------------------------------------------
/cypress/integration/common.js:
--------------------------------------------------------------------------------
1 | import matches from 'lodash/matches';
2 |
3 | export function findMultiAndMatch(count, findObj, matchObj, equalObj, timeout) {
4 | let data = [];
5 | function assert(body) {
6 | data = data.concat(
7 | body?.list?.filter(matches(findObj)).filter(matches(matchObj)) || [],
8 | );
9 | if (data.length < count) {
10 | cy.wait('@post', { timeout }).its('request.body').then(assert);
11 | } else {
12 | data[0] && expect(data[0]).to.nested.include(equalObj);
13 | expect(data.length).to.be.equal(count);
14 | }
15 | }
16 | cy.wait('@post').its('request.body').then(assert);
17 | }
18 |
19 | export function matchMultiAndMatch(
20 | count,
21 | findObj,
22 | matchObj,
23 | equalObj,
24 | timeout = 3000,
25 | ) {
26 | // findMultiAndMatch(count, matches(findObj), matches(matchObj));
27 | findMultiAndMatch(count, findObj, matchObj, equalObj, timeout);
28 | }
29 |
--------------------------------------------------------------------------------
/dev/app-main/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Garfish Demo
6 |
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/packages/browser-snapshot/__tests__/sandbox.spec.ts:
--------------------------------------------------------------------------------
1 | import { Sandbox } from '../src/sandbox';
2 |
3 | describe('test sandbox ', () => {
4 | it('dom sandbox', () => {
5 | document.head.innerHTML = `
6 |
7 | `;
8 |
9 | const obj: {
10 | name: string;
11 | age: string;
12 | some?: string;
13 | } = {
14 | name: 'zhoushaw',
15 | age: '24',
16 | some: 'test delete',
17 | };
18 |
19 | const sb = new Sandbox('app1', [], obj);
20 |
21 | const st = document.createElement('style');
22 | st.style.cssText = 'background: red;';
23 | document.head.appendChild(st);
24 | obj.name = 'wu';
25 | obj.age = '23';
26 | delete obj.some;
27 |
28 | sb.deactivate();
29 |
30 | const result = document.querySelectorAll('style');
31 | expect(result).toMatchSnapshot();
32 | expect(obj).toMatchSnapshot();
33 | });
34 | });
35 |
--------------------------------------------------------------------------------
/dev/app-angular/.browserslistrc:
--------------------------------------------------------------------------------
1 | # This file is used by the build system to adjust CSS and JS output to support the specified browsers below.
2 | # For additional information regarding the format and rule options, please see:
3 | # https://github.com/browserslist/browserslist#queries
4 |
5 | # For the full list of supported browsers by the Angular framework, please see:
6 | # https://angular.io/guide/browser-support
7 |
8 | # You can see what browsers were selected by your queries by running:
9 | # npx browserslist
10 |
11 | last 1 Chrome version
12 | last 1 Firefox version
13 | last 2 Edge major versions
14 | last 2 Safari major versions
15 | last 2 iOS major versions
16 | Firefox ESR
17 | not IE 9-10 # Angular support for IE 9-10 has been deprecated and will be removed as of Angular v11. To opt-in, remove the 'not' prefix on this line.
18 | not IE 11 # Angular supports IE 11 only as an opt-in. To opt-in, remove the 'not' prefix on this line.
19 |
--------------------------------------------------------------------------------
/packages/garfish/__tests__/resources/vueApp.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | vue sub app
5 |
6 |
7 |
8 |
9 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/cypress/support/commands.js:
--------------------------------------------------------------------------------
1 | // ***********************************************
2 | // This example commands.js shows you how to
3 | // create various custom commands and overwrite
4 | // existing commands.
5 | //
6 | // For more comprehensive examples of custom
7 | // commands please read more here:
8 | // https://on.cypress.io/custom-commands
9 | // ***********************************************
10 | //
11 | //
12 | // -- This is a parent command --
13 | // Cypress.Commands.add('login', (email, password) => { ... })
14 | //
15 | //
16 | // -- This is a child command --
17 | // Cypress.Commands.add('drag', { prevSubject: 'element'}, (subject, options) => { ... })
18 | //
19 | //
20 | // -- This is a dual command --
21 | // Cypress.Commands.add('dismiss', { prevSubject: 'optional'}, (subject, options) => { ... })
22 | //
23 | //
24 | // -- This will overwrite an existing command --
25 | // Cypress.Commands.overwrite('visit', (originalFn, url, options) => { ... })
26 |
--------------------------------------------------------------------------------
/website/docs/api/channel.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Garfish.channel
3 | slug: /api/channel
4 | order: 5
5 | ---
6 |
7 | import Highlight from '@site/src/components/Highlight';
8 |
9 | 用于应用间的通信,`Garfish.channel` 为 Garfish 的实例属性,该属性是 [EventEmitter2](https://github.com/EventEmitter2/EventEmitter2) 的实例。
10 |
11 | ### Type
12 |
13 | ```ts
14 | channel: EventEmitter2;
15 | ```
16 |
17 | ### 默认值
18 |
19 | - 无
20 |
21 | ### 示例
22 |
23 | ```js
24 | // 子应用监听登录事件
25 | const App = () => {
26 | const handleLogin = (userInfo) => {
27 | console.log(`${userInfo.name} has login`);
28 | };
29 |
30 | useEffect(() => {
31 | window?.Garfish.channel.on('login', handleLogin);
32 | return () => {
33 | window?.Garfish.channel.removeListener('login', handleLogin);
34 | };
35 | });
36 | };
37 |
38 | // 主应用触发监听事件
39 | api.getLoginInfo.then((res) => {
40 | if (res.code === 0) {
41 | window.Garfish.channel.emit('login', res.data);
42 | }
43 | });
44 | ```
45 |
--------------------------------------------------------------------------------
/dev/app-react-17/src/constant.ts:
--------------------------------------------------------------------------------
1 | export const prefixCls = 'sub-app-react17';
2 |
3 | export const backToMainStr = `
4 | \`\`\`javascript
5 | // window.history.replaceState(null, '', '/examples/main/index');
6 | window.Garfish.router.push({ path: '/main' })
7 | \`\`\`
8 | `;
9 |
10 | export const channelWithMainStr = `
11 | \`\`\`javascript
12 | window?.Garfish?.channel.emit('event', 'hello, 我是 react17 子应用');
13 | \`\`\`
14 | `;
15 |
16 | export const increaseStr = `
17 | \`\`\`javascript
18 | props.store.increment();
19 | \`\`\`
20 | `;
21 |
22 | export const hmrStr = `
23 | \`\`\`javascript
24 |
25 | \`\`\`
26 | `;
27 |
28 | export const toVue3Str = `
29 | \`\`\`javascript
30 | // 子应用间跳转推荐使用 window.history.replaceState 或 Garfish.router.push
31 | // 若使用框架自身路由 api 会默认带上basename
32 |
33 | // 方式一:
34 | window.history.replaceState(null, '', '/examples/vue3/home');
35 |
36 | // 方式二:Garfish.router.push
37 | Garfish.router.push({ path: '/vue3/home' });
38 | \`\`\`
39 | `;
40 |
--------------------------------------------------------------------------------
/dev/config.json:
--------------------------------------------------------------------------------
1 | {
2 | "dev/main": {
3 | "pkgName": "@garfish-dev/main",
4 | "port": 8090
5 | },
6 | "dev/react17": {
7 | "pkgName": "@garfish-dev/react17",
8 | "port": 8091
9 | },
10 | "dev/react16": {
11 | "pkgName": "@garfish-dev/react16",
12 | "port": 8092
13 | },
14 | "dev/react18": {
15 | "pkgName": "@garfish-dev/react18",
16 | "port": 8098
17 | },
18 | "dev/vue3": {
19 | "pkgName": "@garfish-dev/vue3",
20 | "port": 8093
21 | },
22 | "dev/vue2": {
23 | "pkgName": "@garfish-dev/vue2",
24 | "port": 8094
25 | },
26 | "dev/vite": {
27 | "pkgName": "@garfish-dev/vite",
28 | "port": 8095
29 | },
30 | "dev/vue-sub": {
31 | "pkgName": "@garfish-dev/vue-sub",
32 | "port": 8096
33 | },
34 | "dev/angular": {
35 | "pkgName": "@garfish-dev/angular",
36 | "port": 8097
37 | },
38 | "dev/esm": {
39 | "pkgName": "@garfish-dev/esm",
40 | "port": 8099
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/packages/bridge-vue-v3/src/types.d.ts:
--------------------------------------------------------------------------------
1 | export type PropsInfo = {
2 | appName: string;
3 | dom: Element | ShadowRoot | Document;
4 | basename: string;
5 | appRenderInfo: Record;
6 | props: Record;
7 | };
8 |
9 | export type LoadRootComponent = (opts: PropsInfo) => Promise;
10 |
11 | export type TypeComponent =
12 | | {
13 | rootComponent: T;
14 | loadRootComponent?: LoadRootComponent;
15 | }
16 | | {
17 | rootComponent?: T;
18 | loadRootComponent: LoadRootComponent;
19 | };
20 |
21 | export type OptionalType = {
22 | createApp: T;
23 | canUpdate: boolean; // by default, allow parcels created with garfish-react-bridge to be updated
24 | appOptions: (
25 | opts: Record,
26 | ) => Record | Record;
27 | handleInstance: (vueInstance: K, opts: PropsInfo) => void;
28 | };
29 |
30 | export type UserOptions = TypeComponent &
31 | Partial>;
32 |
--------------------------------------------------------------------------------
/dev/app-main/src/static/icons/New.svg:
--------------------------------------------------------------------------------
1 |
7 |
--------------------------------------------------------------------------------
/dev/app-vue-2/vue.config.js:
--------------------------------------------------------------------------------
1 | const { getPublicPath, getPort } = require('../util');
2 | const appName = 'dev/vue2';
3 |
4 | module.exports = {
5 | chainWebpack: (config) => {
6 | config.optimization.delete('splitChunks');
7 | config.module
8 | .rule('images')
9 | .use('url-loader')
10 | .loader('url-loader')
11 | .tap((options) => Object.assign(options, { limit: 1024 }));
12 | },
13 | configureWebpack: () => {
14 | return {
15 | entry: './src/main.ts',
16 | output: {
17 | filename: '[name].[hash].js',
18 | chunkFilename: '[name].[hash].js',
19 | libraryTarget: 'umd',
20 | globalObject: 'window',
21 | },
22 | };
23 | },
24 | publicPath: getPublicPath(appName),
25 | devServer: {
26 | inline: true,
27 | hot: true,
28 | host: '0.0.0.0',
29 | port: getPort(appName),
30 | historyApiFallback: true,
31 | disableHostCheck: true,
32 | headers: {
33 | 'Access-Control-Allow-Origin': '*',
34 | },
35 | },
36 | };
37 |
--------------------------------------------------------------------------------
/dev/app-main/src/components/loadApp/loadAppFunc.tsx:
--------------------------------------------------------------------------------
1 | import Garfish from 'garfish';
2 | import { store } from '../../store';
3 |
4 | export const loadAppFunc = async ({ appName, basename, domID }) => {
5 | let app;
6 | const loadPromise = () => {
7 | const _app: any = store.apps.find((v: any) => v.name === appName);
8 | // 模拟异步请求
9 | return new Promise(async (resolve, reject) => {
10 | setTimeout(async () => {
11 | const app = await Garfish.loadApp(appName, {
12 | entry: _app?.entry,
13 | basename,
14 | domGetter: () => document.getElementById(domID),
15 | // 缓存设置,建议开启缓存避免重复的编译代码造成的性能浪费
16 | cache: true,
17 | });
18 | resolve(app);
19 | }, 1000);
20 | });
21 | };
22 |
23 | const mountApp = async () => {
24 | app = await loadPromise();
25 | // 若已经渲染触发 show,只有首次渲染触发 mount,后面渲染都可以触发 show 提供性能
26 | app && !app.mounted ? await app.mount() : app?.show();
27 | };
28 |
29 | await mountApp();
30 | return app;
31 | };
32 |
--------------------------------------------------------------------------------
/dev/app-vue-vite/src/components/HelloWorld.vue:
--------------------------------------------------------------------------------
1 |
10 |
11 |
12 | {{ msg }}
13 |
14 | Recommended IDE setup:
15 | VSCode
16 | +
17 | Volar
18 |
19 |
20 |
21 |
22 | Vite Documentation
23 |
24 | |
25 | Vue 3 Documentation
26 |
27 |
28 |
29 |
30 | Edit
31 | components/HelloWorld.vue to test hot module replacement.
32 |
33 |
34 |
35 |
40 |
--------------------------------------------------------------------------------
/packages/router/src/utils/index.ts:
--------------------------------------------------------------------------------
1 | import { RouterHook } from '../config';
2 |
3 | export async function asyncForEach(
4 | arr: T[],
5 | callback: (v: T, k: number, O: T[]) => Promise,
6 | ) {
7 | const length = arr.length;
8 | let k = 0;
9 | while (k < length) {
10 | const kValue = arr[k];
11 | await callback(kValue, k, arr);
12 | k++;
13 | }
14 | }
15 |
16 | export function toMiddleWare(to, from, cb: RouterHook) {
17 | return new Promise((resolve, reject) => {
18 | try {
19 | cb(to, from, resolve);
20 | } catch (err) {
21 | reject(err);
22 | }
23 | });
24 | }
25 |
26 | export function createEvent(type) {
27 | let e;
28 | // Compatible with ie
29 | if (
30 | navigator.userAgent.indexOf('MSIE') !== -1 ||
31 | navigator.appVersion.indexOf('Trident/') > 0
32 | ) {
33 | e = document.createEvent('UIEvents');
34 | e.initUIEvent(type.toLowerCase(), true, false, window, 0);
35 | } else {
36 | e = new Event(type.toLowerCase());
37 | }
38 | return e;
39 | }
40 |
--------------------------------------------------------------------------------
/dev/app-vue/vue.config.js:
--------------------------------------------------------------------------------
1 | const { getPublicPath, getPort } = require('../util');
2 | const appName = 'dev/vue-sub';
3 |
4 | module.exports = {
5 | chainWebpack: (config) => {
6 | config.optimization.delete('splitChunks');
7 | config.module
8 | .rule('images')
9 | .use('url-loader')
10 | .loader('url-loader')
11 | .tap((options) => Object.assign(options, { limit: 1024 }));
12 | },
13 | configureWebpack: () => {
14 | return {
15 | entry: './src/main.js',
16 | output: {
17 | filename: '[name].[hash].js',
18 | chunkFilename: '[name].[hash].js',
19 | libraryTarget: 'umd',
20 | globalObject: 'window',
21 | },
22 | };
23 | },
24 | publicPath: getPublicPath(appName),
25 |
26 | devServer: {
27 | inline: true,
28 | hot: true,
29 | host: '0.0.0.0',
30 | port: getPort(appName),
31 | historyApiFallback: true,
32 | disableHostCheck: true,
33 | headers: {
34 | 'Access-Control-Allow-Origin': '*',
35 | },
36 | },
37 | };
38 |
--------------------------------------------------------------------------------
/jest.config.js:
--------------------------------------------------------------------------------
1 | // For a detailed explanation regarding each configuration property, visit:
2 | // https://jestjs.io/docs/en/configuration.html
3 |
4 | module.exports = {
5 | clearMocks: true,
6 | testTimeout: 20000,
7 | testEnvironment: 'jsdom',
8 | preset: 'jest-puppeteer',
9 | coverageDirectory: 'coverage',
10 | coveragePathIgnorePatterns: ['__tests__', '/node_modules/'],
11 | coverageProvider: 'v8',
12 | globals: {
13 | __DEV__: true,
14 | __TEST__: true,
15 | __VERSION__: '"unknow"',
16 | },
17 | preset: 'ts-jest',
18 | transformIgnorePatterns: [
19 | // Change MODULE_NAME_HERE to your module that isn't being compiled
20 | '/node_modules/(?!(@garfish)).+\\.js$',
21 | ],
22 | transform: {
23 | '^.+\\.(t|j)sx?$': ['@swc/jest'],
24 | },
25 | rootDir: __dirname,
26 | testMatch: ['/packages/**/__tests__/**/*spec.[jt]s?(x)'],
27 | testPathIgnorePatterns: ['/node_modules/', '/dev/'],
28 | moduleNameMapper: {
29 | '@garfish/(.*)': 'packages/$1/src',
30 | },
31 | };
32 |
--------------------------------------------------------------------------------
/website/docs/api/api.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: 概览
3 | slug: /api
4 | order: 1
5 | ---
6 |
7 | ```ts
8 | import Garfish from "garfish";
9 | ```
10 | 在主应用中,我们通过 `import Garfish from "garfish";` 来引入 Garfish,并调用相关 Garfish api 去注册子应用或运行微前端应用。
11 |
12 | 其中,Garfish 是 `garfish` 包默认导出的实例,实例上包含微前端相关API,用户可以通过相应 API 完成对整个微前端应用的管理。
13 |
14 | :::tip
15 | 这里需要特殊说明的是,子应用不需要额外引入 Garfish 实例,子应用可通过 `window.Garfish` 获取全局 Garfish 实例信息,参考 [Garfish 环境变量](../guide/quickStart/env.md)。
16 | :::
17 |
18 |
19 | ## Garfish 实例方法
20 | - [Garfish.run](/api/run) (用于初始化应用参数、启动路由监听,当路由发生变化时自动激活应用或销毁应用)
21 | - [Garfish.registerApp](/api/registerapp)(用于动态注册应用信息)
22 | - [Garfish.loadApp](/api/loadapp)(可以手动控制子应用加载和销毁)
23 | - [Garfish.router](/api/router)(提供路由跳转和路由守卫能力)
24 | - [Garfish.channel](/api/channel)(提供应用间通信的能力)
25 | - [Garfish.setExternal](/api/setexternal)(支持应用间的依赖共享)
26 | - [Garfish.getGlobalObject](/api/getglobalobject)(用于获取真实 Window)
27 | - [Garfish.setGlobalObject](/api/getglobalobject)(用于设置真实 Window 的值)
28 | - [Garfish.clearEscapeEffect](/api/getglobalobject)(用于清除逃逸的副作用)
29 |
--------------------------------------------------------------------------------
/packages/remote-module/src/apis/preload.ts:
--------------------------------------------------------------------------------
1 | import { assert, isAbsolute } from '@garfish/utils';
2 | import { hooks } from '../hooks';
3 | import { processAlias } from './setModuleConfig';
4 | import { loader, resourcesStore } from '../common';
5 |
6 | // Preload the static resources of the module, so that the module can be loaded synchronously
7 | export function preload(urls: string | Array) {
8 | if (!Array.isArray(urls)) urls = [urls];
9 |
10 | return Promise.all(
11 | urls.map((url) => {
12 | url = processAlias(url)[0];
13 | assert(
14 | isAbsolute(url),
15 | `The loading of the remote module must be an absolute path. "${url}"`,
16 | );
17 | return loader.loadModule(url).then((data) => {
18 | if (data.resourceManager) {
19 | data.resourceManager.originUrl = url;
20 | resourcesStore.push(data.resourceManager);
21 | hooks.lifecycle.preloaded.emit(data.resourceManager);
22 | }
23 | return data;
24 | });
25 | }),
26 | );
27 | }
28 |
--------------------------------------------------------------------------------
/packages/es-module/__tests__/case/exportNamespace/m1.js:
--------------------------------------------------------------------------------
1 | import * as m2 from './m2.js';
2 | import * as m3 from './m3.js';
3 | import * as m5 from './m5.js';
4 | import m2Default from './m2.js';
5 | import { d } from './m2.js';
6 |
7 | // 模块对象是不能扩展的
8 | expect(() => {
9 | m2.toString = () => {};
10 | }).toThrow();
11 | // 模块对象的原型为 null
12 | expect(Object.getPrototypeOf(m2)).toBe(null);
13 |
14 | expect(m2.toString).toBeUndefined();
15 | expect(m2[Symbol.toStringTag]).toBe('Module');
16 |
17 | expect(d).toBe(1);
18 | expect(m2Default).toEqual([3]);
19 |
20 | expect(Object.keys(m2).length).toBe(10);
21 | expect(m2._name).toBe('m2');
22 | expect(m2.a).toEqual([1]);
23 | expect(m2.b).toEqual([2]);
24 | expect(m2.d).toBe(1);
25 | expect(m2.default).toEqual([3]);
26 | expect(m2.m3Namespace === m3).toBe(true);
27 | expect(m2.n1).toBe('m3');
28 | expect(m2.n2).toBe('m3');
29 | expect(m2.name).toBe('m3');
30 | expect(m2.nn).toBe('m3');
31 |
32 | // export * 中有相同的字段,会被忽略,default 字段也会被忽略
33 | expect('name' in m5).toBe(false);
34 | expect('default' in m5).toBe(false);
35 |
--------------------------------------------------------------------------------
/scripts/verifyCommit.js:
--------------------------------------------------------------------------------
1 | const fs = require('fs');
2 | const chalk = require('chalk');
3 | const msgPath = process.env.HUSKY_GIT_PARAMS;
4 | const msg = fs.readFileSync(msgPath, 'utf-8').trim();
5 | const ng =
6 | 'https://docs.google.com/document/d/1QrDFcIiPjSLDn3EL15IJygNPiHORgU1_OOAqWjiDU5Y/edit#heading=h.greljkmo14y0';
7 | const commitRE =
8 | /^(revert: )?(feat|fix|docs|dx|style|refactor|perf|test|workflow|build|ci|chore|types|wip|release)(\(.+\))?: .{1,50}/;
9 |
10 | if (!commitRE.test(msg)) {
11 | console.log();
12 | console.error(
13 | ` ${chalk.bgRed.white(' ERROR ')} ${chalk.red(
14 | 'invalid commit message format.',
15 | )}\n\n` +
16 | chalk.red(
17 | ' Proper commit message format is required for automated changelog generation. Examples:\n\n',
18 | ) +
19 | ` ${chalk.green('feat(compiler): add `comments` option')}\n` +
20 | ` ${chalk.green('fix(event): handle events error (close #28)')}\n\n` +
21 | chalk.red(` See '${ng}' for more details.\n`),
22 | );
23 | process.exit(1);
24 | }
25 |
--------------------------------------------------------------------------------
/dev/app-vue-3/vue.config.js:
--------------------------------------------------------------------------------
1 | const { getPublicPath, getPort } = require('../util');
2 | const appName = 'dev/vue3';
3 |
4 | module.exports = {
5 | chainWebpack: (config) => {
6 | config.optimization.delete('splitChunks');
7 | config.module
8 | .rule('images')
9 | .use('url-loader')
10 | .loader('url-loader')
11 | .tap((options) => Object.assign(options, { limit: 1024 }));
12 | },
13 | configureWebpack: () => {
14 | return {
15 | entry: './src/main.ts',
16 | output: {
17 | filename: '[name].[hash].js',
18 | chunkFilename: '[name].[hash].js',
19 | libraryTarget: 'umd',
20 | globalObject: 'window',
21 | },
22 | };
23 | },
24 | publicPath: getPublicPath(appName),
25 | devServer: {
26 | inline: true,
27 | hot: true,
28 | host: '0.0.0.0',
29 | port: getPort(appName),
30 | historyApiFallback: true,
31 | allowedHosts: ['all'],
32 | disableHostCheck: true,
33 | headers: {
34 | 'Access-Control-Allow-Origin': '*',
35 | },
36 | },
37 | };
38 |
--------------------------------------------------------------------------------
/dev/app-angular/e2e/protractor.conf.js:
--------------------------------------------------------------------------------
1 | // @ts-check
2 | // Protractor configuration file, see link for more information
3 | // https://github.com/angular/protractor/blob/master/lib/config.ts
4 |
5 | const { SpecReporter, StacktraceOption } = require('jasmine-spec-reporter');
6 |
7 | /**
8 | * @type { import("protractor").Config }
9 | */
10 | exports.config = {
11 | allScriptsTimeout: 11000,
12 | specs: ['./src/**/*.e2e-spec.ts'],
13 | capabilities: {
14 | browserName: 'chrome',
15 | },
16 | directConnect: true,
17 | baseUrl: 'http://localhost:8097/',
18 | framework: 'jasmine',
19 | jasmineNodeOpts: {
20 | showColors: true,
21 | defaultTimeoutInterval: 30000,
22 | print: function () {},
23 | },
24 | onPrepare() {
25 | require('ts-node').register({
26 | project: require('path').join(__dirname, './tsconfig.json'),
27 | });
28 | jasmine.getEnv().addReporter(
29 | new SpecReporter({
30 | spec: {
31 | displayStacktrace: StacktraceOption.PRETTY,
32 | },
33 | }),
34 | );
35 | },
36 | };
37 |
--------------------------------------------------------------------------------
/packages/browser-snapshot/src/patchers/multithread.ts:
--------------------------------------------------------------------------------
1 | import { Snapshot } from './interceptor';
2 | export class MultithreadInterceptor {
3 | snapshotBefore: Snapshot;
4 | targetToProtect: HTMLElement;
5 | uuid: string;
6 | constructor() {
7 | this.uuid = '' + -new Date();
8 | this.targetToProtect.setAttribute('gar', this.uuid);
9 | }
10 | beforeAdd() {
11 | this.snapshotBefore = Snapshot.take(document.getElementsByTagName('style'));
12 | }
13 | afterAdd() {
14 | const now = Snapshot.take(document.getElementsByTagName('style'));
15 | const diff = this.snapshotBefore.diff(now);
16 | diff.created.arrDoms.forEach((styleElement: HTMLStyleElement) => {
17 | const styleSheet: CSSStyleSheet = styleElement.sheet as CSSStyleSheet;
18 | if (!styleSheet.cssRules) {
19 | return;
20 | }
21 | for (
22 | let i = 0, rule: CSSStyleRule;
23 | (rule = styleSheet.cssRules[i] as CSSStyleRule);
24 | i++
25 | ) {
26 | rule.selectorText += `[gar=${this.uuid}] `;
27 | }
28 | });
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/packages/bridge-vue-v2/src/types.d.ts:
--------------------------------------------------------------------------------
1 | export type PropsInfo = {
2 | appName: string;
3 | dom: Element | ShadowRoot | Document;
4 | basename: string;
5 | appRenderInfo: Record;
6 | props: Record;
7 | };
8 |
9 | export type LoadRootComponent = (opts: PropsInfo) => Promise;
10 |
11 | export type TypeComponent =
12 | | {
13 | rootComponent: T;
14 | loadRootComponent?: LoadRootComponent;
15 | }
16 | | {
17 | rootComponent?: T;
18 | loadRootComponent: LoadRootComponent;
19 | };
20 |
21 | export type OptionalType any> = {
22 | Vue: T;
23 | canUpdate: boolean; // by default, allow parcels created with garfish-react-bridge to be updated
24 | appOptions: (
25 | opts: Record,
26 | ) => Record | Record;
27 | handleInstance: (vueInstance: InstanceType, opts: PropsInfo) => void;
28 | };
29 |
30 | export type UserOptions<
31 | T extends new (...args: any) => any,
32 | U,
33 | > = TypeComponent & Partial>;
34 |
--------------------------------------------------------------------------------
/dev/app-react-17/src/components/detail/index.tsx:
--------------------------------------------------------------------------------
1 | import { useSearchParams, useNavigate } from 'react-router-dom';
2 | import { detail } from '../constant';
3 | import { Descriptions, Breadcrumb } from '@arco-design/web-react';
4 | import './index.less';
5 |
6 | const BreadcrumbItem = Breadcrumb.Item;
7 |
8 | const Detail = () => {
9 | const navigate = useNavigate();
10 | const [searchParams] = useSearchParams();
11 | const content = searchParams.get('id') && detail[searchParams.get('id')!];
12 |
13 | return (
14 |
30 | );
31 | };
32 |
33 | export default Detail;
34 |
--------------------------------------------------------------------------------
/dev/app-vue/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "baseUrl": ".",
4 | "outDir": "build",
5 | "target": "esnext",
6 | "module": "esnext",
7 | "strict": true,
8 | "lib": ["esnext", "dom", "dom.iterable", "scripthost"],
9 | "experimentalDecorators": true,
10 | "sourceMap": true,
11 | "allowJs": false,
12 | "jsx": "react-jsx",
13 | "moduleResolution": "node",
14 | "resolveJsonModule": true,
15 | "forceConsistentCasingInFileNames": true,
16 | "noImplicitReturns": true,
17 | "noImplicitThis": true,
18 | "noImplicitAny": false,
19 | "strictNullChecks": true,
20 | "suppressImplicitAnyIndexErrors": true,
21 | "esModuleInterop": true,
22 | "skipLibCheck": true,
23 | "skipDefaultLibCheck": true,
24 | "isolatedModules": false,
25 | "noUnusedLocals": true,
26 | "plugins": [
27 | {
28 | "name": "typescript-styled-plugin"
29 | }
30 | ]
31 | },
32 | "exclude": ["node_modules"],
33 | "include": [
34 | "src",
35 | ],
36 | "paths": {
37 | "@/*": ["src/*"]
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/dev/app-vue-2/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "baseUrl": ".",
4 | "outDir": "build",
5 | "target": "esnext",
6 | "module": "esnext",
7 | "strict": true,
8 | "lib": ["esnext", "dom", "dom.iterable", "scripthost"],
9 | "experimentalDecorators": true,
10 | "sourceMap": true,
11 | "allowJs": false,
12 | "jsx": "react-jsx",
13 | "moduleResolution": "node",
14 | "resolveJsonModule": true,
15 | "forceConsistentCasingInFileNames": true,
16 | "noImplicitReturns": true,
17 | "noImplicitThis": true,
18 | "noImplicitAny": false,
19 | "strictNullChecks": true,
20 | "suppressImplicitAnyIndexErrors": true,
21 | "esModuleInterop": true,
22 | "skipLibCheck": true,
23 | "skipDefaultLibCheck": true,
24 | "isolatedModules": false,
25 | "noUnusedLocals": true,
26 | "plugins": [
27 | {
28 | "name": "typescript-styled-plugin"
29 | }
30 | ]
31 | },
32 | "exclude": ["node_modules"],
33 | "include": [
34 | "src",
35 | ],
36 | "paths": {
37 | "@/*": ["src/*"]
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/dev/app-vue-3/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "baseUrl": ".",
4 | "outDir": "build",
5 | "target": "esnext",
6 | "module": "esnext",
7 | "strict": true,
8 | "lib": ["esnext", "dom", "dom.iterable", "scripthost"],
9 | "experimentalDecorators": true,
10 | "sourceMap": true,
11 | "allowJs": false,
12 | "jsx": "react-jsx",
13 | "moduleResolution": "node",
14 | "resolveJsonModule": true,
15 | "forceConsistentCasingInFileNames": true,
16 | "noImplicitReturns": true,
17 | "noImplicitThis": true,
18 | "noImplicitAny": false,
19 | "strictNullChecks": true,
20 | "suppressImplicitAnyIndexErrors": true,
21 | "esModuleInterop": true,
22 | "skipLibCheck": true,
23 | "skipDefaultLibCheck": true,
24 | "isolatedModules": false,
25 | "noUnusedLocals": true,
26 | "plugins": [
27 | {
28 | "name": "typescript-styled-plugin"
29 | }
30 | ]
31 | },
32 | "exclude": ["node_modules"],
33 | "include": [
34 | "src",
35 | ],
36 | "paths": {
37 | "@/*": ["src/*"]
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/packages/bridge-vue-v3/README.md:
--------------------------------------------------------------------------------
1 | # `@garfish/bridge-vue-v3`
2 |
3 | [](https://www.npmjs.com/package/@garfish/bridge-vue-v3)
4 |
5 | Vue bridge for vue v3 subapp. For more details, [check here](https://www.garfishjs.org/guide/bridge)
6 | ## Usage
7 |
8 | ```jsx
9 | // child app
10 | import { vueBridge } from '@garfish/bridge-vue-v3';
11 |
12 | function App() {
13 | return content
;
14 | }
15 |
16 | export const provider = vueBridge({
17 | rootComponent: App,
18 | appOptions: ({ basename, dom, appName, props }) => {
19 | // pass the options to createApp. check hhttps://vuejs.org/api/application.html#createApp
20 | return {
21 | el: '#app',
22 | render: () => h(App),
23 | };
24 | },
25 | handleInstance: (vueInstance, { basename, dom, appName, props }) => {
26 | // you can do something in handleInstance after get the vueInstance
27 | vueInstance.use(newRouter(basename));
28 | vueInstance.provide(stateSymbol, createState());
29 | },
30 | });
31 |
32 | ```
33 |
--------------------------------------------------------------------------------
/packages/browser-snapshot/src/patchers/interval.ts:
--------------------------------------------------------------------------------
1 | const rawInterval = window.setInterval;
2 | const rawClearInterval = window.clearInterval;
3 |
4 | export class PatchInterval {
5 | private intervals: Array = [];
6 | constructor() {}
7 |
8 | public activate() {
9 | // @ts-ignore
10 | window.setInterval = (
11 | handler: Function,
12 | timeout?: number,
13 | ...args: any[]
14 | ) => {
15 | const intervalId = rawInterval(handler, timeout, ...args);
16 | this.intervals = [...this.intervals, intervalId];
17 | return intervalId;
18 | };
19 |
20 | // @ts-ignore
21 | window.clearInterval = (intervalId: number) => {
22 | this.intervals = this.intervals.filter((id) => id !== intervalId);
23 | return rawClearInterval(intervalId);
24 | };
25 | }
26 |
27 | public deactivate(_clearEffects?: boolean) {
28 | if (_clearEffects) {
29 | this.intervals.forEach((id) => window.clearInterval(id));
30 | }
31 | window.setInterval = rawInterval;
32 | window.clearInterval = rawClearInterval;
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/packages/es-module/README.md:
--------------------------------------------------------------------------------
1 | # `@garfish/es-module`
2 |
3 | [](https://www.npmjs.com/package/@garfish/es-module)
4 |
5 | Inspired by [virtual-es-module](https://github.com/imtaotao/virtual-es-module).
6 |
7 | ## Usage
8 |
9 | ```js
10 | import Runtime from '@garfish/es-module';
11 | // One runtime, one project
12 | const runtime = new Runtime();
13 |
14 | const module = await runtime.importByUrl('./a.mjs');
15 | console.log(module);
16 |
17 | const module = await runtime.importByCode(`
18 | import * as m from './a.mjs';
19 | export default 1;
20 | `);
21 | console.log(module);
22 | ```
23 |
24 | ## Use in Garfish
25 |
26 | `@garfish/es-module` will bring serious above-the-fold performance problems, child applications should not use `esModule` in production environments.
27 |
28 | ```js
29 | import { GarfishEsModule } from '@garfish/es-module';
30 |
31 | Garfish.run({
32 | ...
33 | plugins: [
34 | ...
35 | GarfishEsModule({
36 | excludes: ['appName'],
37 | }),
38 | ],
39 | })
40 | ```
41 |
--------------------------------------------------------------------------------
/dev/app-react-18/src/root.tsx:
--------------------------------------------------------------------------------
1 | import { ConfigProvider } from '@arco-design/web-react';
2 | import { BrowserRouter, Routes, Route } from 'react-router-dom';
3 | import App from './App';
4 | import PageNotFound from './PageNotFound';
5 | import './App.less';
6 | import { AppInfo } from '@garfish/bridge-react-v18';
7 |
8 | export const prefixCls = 'sub-app-react16';
9 |
10 | const Index = This is Home Page.
;
11 | const About = This is About Page.
;
12 |
13 | const RootComponent = (appInfo: AppInfo) => {
14 | const routes = (
15 |
16 | }>
17 |
18 |
19 | } />
20 |
21 |
22 | );
23 | return (
24 |
25 | {routes}
26 |
27 | );
28 | };
29 |
30 | export default RootComponent;
31 |
--------------------------------------------------------------------------------
/dev/app-vue-3/src/store.js:
--------------------------------------------------------------------------------
1 | import { reactive, readonly, provide, inject } from 'vue';
2 |
3 | export const stateSymbol = Symbol('state');
4 | export const incrementSymbol = Symbol('increment');
5 |
6 | export const createState = () => {
7 | const state = reactive({
8 | counter: 0,
9 | id: 1,
10 | todos: [{ id: 1, text: 'default todo', done: false }],
11 | });
12 |
13 | const increment = () => state.counter++;
14 |
15 | const done = (id) => {
16 | state.todos = state.todos.filter((item) => item.id !== id);
17 | };
18 |
19 | const add = (item) => {
20 | state.id += 1;
21 | item.id = state.id;
22 | // item.id = state.todos.length + 1;
23 | state.todos.push(item);
24 | console.log('state.todos', state.todos);
25 | };
26 |
27 | const getDoneTodos = (state) => {
28 | return state.todos.filter((todo) => todo.done);
29 | };
30 |
31 | return { increment, done, add, getDoneTodos, state: readonly(state) };
32 | };
33 |
34 | export const useState = () => inject(stateSymbol);
35 |
36 | export const provideState = () => provide(stateSymbol, createState());
37 |
--------------------------------------------------------------------------------
/packages/remote-module/src/hooks.ts:
--------------------------------------------------------------------------------
1 | import type { ModuleManager } from '@garfish/loader';
2 | import {
3 | PluginSystem,
4 | SyncHook,
5 | SyncWaterfallHook,
6 | AsyncWaterfallHook,
7 | } from '@garfish/hooks';
8 | import type { Actuator } from './actuator';
9 | import type { ModuleConfig, ModuleInfo } from './common';
10 |
11 | export interface BeforeLoadArgs {
12 | url: string;
13 | options?: ModuleConfig;
14 | }
15 |
16 | export interface afterLoadArgs {
17 | url: string;
18 | code: string;
19 | exports: Record;
20 | }
21 |
22 | export const hooks = new PluginSystem({
23 | preloaded: new SyncHook<[ModuleManager], any>(),
24 | initModule: new SyncHook<[Actuator], any>('initModule'),
25 | beforeLoadModule: new SyncWaterfallHook('beforeLoadModule'),
26 | asyncBeforeLoadModule: new AsyncWaterfallHook(
27 | 'asyncBeforeLoadModule',
28 | ),
29 | afterLoadModule: new SyncWaterfallHook('afterLoadModule'),
30 | asyncAfterLoadModule: new AsyncWaterfallHook(
31 | 'asyncAfterLoadModule',
32 | ),
33 | });
34 |
--------------------------------------------------------------------------------
/packages/core/__tests__/resources/asyncProviderApp.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | async provider app
5 |
6 |
7 |
8 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/dev/app-angular/README.md:
--------------------------------------------------------------------------------
1 | # Angular
2 |
3 | This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 10.2.0.
4 |
5 | ## Development server
6 |
7 | Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files.
8 |
9 | ## Code scaffolding
10 |
11 | Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`.
12 |
13 | ## Build
14 |
15 | Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. Use the `--prod` flag for a production build.
16 |
17 | ## Running unit tests
18 |
19 | Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io).
20 |
21 | ## Running end-to-end tests
22 |
23 | Run `ng e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/).
24 |
25 | ## Further help
26 |
27 | To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI Overview and Command Reference](https://angular.io/cli) page.
28 |
--------------------------------------------------------------------------------
/packages/browser-vm/src/lifecycle.ts:
--------------------------------------------------------------------------------
1 | import { SyncHook, PluginSystem } from '@garfish/hooks';
2 | import type { interfaces } from '@garfish/core';
3 | import type { FakeWindow } from './types';
4 |
5 | export function sandboxLifecycle() {
6 | return new PluginSystem({
7 | closed: new SyncHook<[], void>(),
8 | stared: new SyncHook<[FakeWindow?], void>(),
9 | appendNode: new SyncHook<[Element, Element, Element, string], void>(),
10 | beforeClearEffect: new SyncHook<[], void>(),
11 | afterClearEffect: new SyncHook<[], void>(),
12 | beforeInvoke: new SyncHook<
13 | [
14 | { code: string },
15 | string?,
16 | Record?,
17 | interfaces.ExecScriptOptions?,
18 | ],
19 | void
20 | >(),
21 | afterInvoke: new SyncHook<
22 | [
23 | { code: string },
24 | string?,
25 | Record?,
26 | interfaces.ExecScriptOptions?,
27 | ],
28 | void
29 | >(),
30 | invokeError: new SyncHook<
31 | [Error, string?, Record?, interfaces.ExecScriptOptions?],
32 | void
33 | >(),
34 | });
35 | }
36 |
--------------------------------------------------------------------------------
/dev/app-main/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "baseUrl": ".",
4 | "outDir": "build",
5 | "target": "esnext",
6 | "module": "esnext",
7 | "strict": true,
8 | "lib": ["esnext", "dom", "dom.iterable", "scripthost"],
9 | "experimentalDecorators": true,
10 | "sourceMap": true,
11 | "allowJs": false,
12 | "jsx": "react-jsx",
13 | "moduleResolution": "node",
14 | "resolveJsonModule": true,
15 | "forceConsistentCasingInFileNames": true,
16 | "noImplicitReturns": true,
17 | "noImplicitThis": true,
18 | "noImplicitAny": false,
19 | "strictNullChecks": true,
20 | "suppressImplicitAnyIndexErrors": true,
21 | "esModuleInterop": true,
22 | "skipLibCheck": true,
23 | "skipDefaultLibCheck": true,
24 | "isolatedModules": false,
25 | "noUnusedLocals": true,
26 | "plugins": [
27 | {
28 | "name": "typescript-styled-plugin"
29 | }
30 | ]
31 | },
32 | "exclude": ["node_modules"],
33 | "include": [
34 | "src/**/*.ts",
35 | "src/**/*.tsx",
36 | "./typings.d.ts"
37 | ],
38 | "paths": {
39 | "@/*": ["src/*"]
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/dev/app-react-16/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "baseUrl": ".",
4 | "outDir": "build",
5 | "target": "esnext",
6 | "module": "esnext",
7 | "strict": true,
8 | "lib": ["esnext", "dom", "dom.iterable", "scripthost"],
9 | "experimentalDecorators": true,
10 | "sourceMap": true,
11 | "allowJs": false,
12 | "jsx": "react",
13 | "moduleResolution": "node",
14 | "resolveJsonModule": true,
15 | "forceConsistentCasingInFileNames": true,
16 | "noImplicitReturns": true,
17 | "noImplicitThis": true,
18 | "noImplicitAny": false,
19 | "strictNullChecks": true,
20 | "suppressImplicitAnyIndexErrors": true,
21 | "esModuleInterop": true,
22 | "skipLibCheck": true,
23 | "skipDefaultLibCheck": true,
24 | "isolatedModules": false,
25 | "noUnusedLocals": true,
26 | "plugins": [
27 | {
28 | "name": "typescript-styled-plugin"
29 | }
30 | ]
31 | },
32 | "exclude": ["node_modules"],
33 | "include": [
34 | "src/**/*.ts",
35 | "src/**/*.tsx",
36 | "./typings.d.ts"
37 | ],
38 | "paths": {
39 | "@/*": ["src/*"]
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/dev/app-main/src/garfishInit.ts:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Garfish from 'garfish';
3 | import * as ReactDom from 'react-dom';
4 | import * as mobxReact from 'mobx-react';
5 | import * as ReactRouterDom from 'react-router-dom';
6 | import { Message } from '@arco-design/web-react';
7 | import { store } from './store';
8 | import { Config } from './config';
9 | import { localApps } from './constant';
10 |
11 | export const GarfishInit = async () => {
12 | const apps = localApps;
13 | console.log('Garfish.run apps', apps);
14 | store.setApps(apps);
15 | Garfish.setExternal({
16 | react: React,
17 | 'react-dom': ReactDom,
18 | 'react-router-dom': ReactRouterDom,
19 | 'mobx-react': mobxReact,
20 | });
21 |
22 | Garfish.channel.on('event', (msg: string) => {
23 | Message.success(`主应用收到消息:${msg}`);
24 | });
25 |
26 | Garfish.router.beforeEach((to, from, next) => {
27 | next();
28 | });
29 |
30 | Garfish.router.afterEach((to, from, next) => {
31 | next();
32 | });
33 |
34 | try {
35 | Garfish.run(Config);
36 | } catch (error) {
37 | console.log('garfish init error', error);
38 | }
39 | };
40 |
--------------------------------------------------------------------------------
/dev/app-react-17/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "baseUrl": ".",
4 | "outDir": "build",
5 | "target": "esnext",
6 | "module": "esnext",
7 | "strict": true,
8 | "lib": ["esnext", "dom", "dom.iterable", "scripthost"],
9 | "experimentalDecorators": true,
10 | "sourceMap": true,
11 | "allowJs": false,
12 | "jsx": "react-jsx",
13 | "moduleResolution": "node",
14 | "resolveJsonModule": true,
15 | "forceConsistentCasingInFileNames": true,
16 | "noImplicitReturns": true,
17 | "noImplicitThis": true,
18 | "noImplicitAny": false,
19 | "strictNullChecks": true,
20 | "suppressImplicitAnyIndexErrors": true,
21 | "esModuleInterop": true,
22 | "skipLibCheck": true,
23 | "skipDefaultLibCheck": true,
24 | "isolatedModules": false,
25 | "noUnusedLocals": true,
26 | "plugins": [
27 | {
28 | "name": "typescript-styled-plugin"
29 | }
30 | ]
31 | },
32 | "exclude": ["node_modules"],
33 | "include": [
34 | "src/**/*.ts",
35 | "src/**/*.tsx",
36 | "./typings.d.ts"
37 | ],
38 | "paths": {
39 | "@/*": ["src/*"]
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/dev/app-react-18/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "baseUrl": ".",
4 | "outDir": "build",
5 | "target": "esnext",
6 | "module": "esnext",
7 | "strict": true,
8 | "lib": ["esnext", "dom", "dom.iterable", "scripthost"],
9 | "experimentalDecorators": true,
10 | "sourceMap": true,
11 | "allowJs": false,
12 | "jsx": "react-jsx",
13 | "moduleResolution": "node",
14 | "resolveJsonModule": true,
15 | "forceConsistentCasingInFileNames": true,
16 | "noImplicitReturns": true,
17 | "noImplicitThis": true,
18 | "noImplicitAny": false,
19 | "strictNullChecks": true,
20 | "suppressImplicitAnyIndexErrors": true,
21 | "esModuleInterop": true,
22 | "skipLibCheck": true,
23 | "skipDefaultLibCheck": true,
24 | "isolatedModules": false,
25 | "noUnusedLocals": true,
26 | "plugins": [
27 | {
28 | "name": "typescript-styled-plugin"
29 | }
30 | ]
31 | },
32 | "exclude": ["node_modules"],
33 | "include": [
34 | "src/**/*.ts",
35 | "src/**/*.tsx",
36 | "./typings.d.ts"
37 | ],
38 | "paths": {
39 | "@/*": ["src/*"]
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/packages/core/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Bytedance Inc.
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/packages/hooks/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@garfish/hooks",
3 | "version": "1.8.2",
4 | "description": "hooks module.",
5 | "keywords": [
6 | "garfish",
7 | "hooks"
8 | ],
9 | "author": "chentao.arthur ",
10 | "homepage": "http://garfish.bytedance.com",
11 | "license": "MIT",
12 | "exports": {
13 | ".": {
14 | "import": "./dist/esm/index.js",
15 | "require": "./dist/index.js"
16 | },
17 | "./*": "./*"
18 | },
19 | "main": "dist/index.js",
20 | "module": "dist/esm/index.js",
21 | "types": "./src/index.ts",
22 | "scripts": {
23 | "build": "rimraf dist && tsup src/index.ts",
24 | "dev": "cross-env WATCH=true tsup src/index.ts"
25 | },
26 | "dependencies": {
27 | "@garfish/utils": "workspace:*"
28 | },
29 | "repository": {
30 | "type": "git",
31 | "url": "git+https://github.com/bytedance/garfish.git"
32 | },
33 | "bugs": {
34 | "url": "https://github.com/bytedance/garfish/issues"
35 | },
36 | "publishConfig": {
37 | "registry": "https://registry.npmjs.org",
38 | "access": "public",
39 | "types": "./dist/index.d.ts"
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/packages/es-module/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Bytedance Inc.
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/packages/garfish/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Bytedance Inc.
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/packages/hooks/src/syncHook.ts:
--------------------------------------------------------------------------------
1 | import { warn } from '@garfish/utils';
2 |
3 | export type Callback = (...args: ArgsType) => K;
4 | export type ArgsType = T extends Array ? T : Array;
5 |
6 | export class SyncHook {
7 | public type: string = '';
8 | public listeners = new Set>();
9 |
10 | constructor(type?: string) {
11 | if (type) this.type = type;
12 | }
13 |
14 | on(fn: Callback) {
15 | if (typeof fn === 'function') {
16 | this.listeners.add(fn);
17 | } else if (__DEV__) {
18 | warn('Invalid parameter in "Hook".');
19 | }
20 | }
21 |
22 | once(fn: Callback) {
23 | const self = this;
24 | this.on(function wrapper(...args: Array) {
25 | self.remove(wrapper);
26 | return fn.apply(null, args);
27 | });
28 | }
29 |
30 | emit(...data: ArgsType) {
31 | if (this.listeners.size > 0) {
32 | this.listeners.forEach((fn) => fn.apply(null, data));
33 | }
34 | }
35 |
36 | remove(fn: Callback) {
37 | return this.listeners.delete(fn);
38 | }
39 |
40 | removeAll() {
41 | this.listeners.clear();
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/packages/loader/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Bytedance Inc.
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/packages/router/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Bytedance Inc.
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/packages/utils/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Bytedance Inc.
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/cypress/integration/2-the-vm-sandbox/set-global-variable.spec.js:
--------------------------------------------------------------------------------
1 | ///
2 |
3 | const basename = '/examples';
4 |
5 | describe('whole process vm sandbox set variable', () => {
6 | beforeEach(() => {
7 | Cypress.env({
8 | garfishRunConfig: {
9 | basename: basename,
10 | disablePreloadApp: true,
11 | sandbox: {
12 | snapshot: false,
13 | },
14 | },
15 | });
16 | });
17 |
18 | it('set global history variable', () => {
19 | const ProxyVariableTitle = 'vm sandbox';
20 | cy.visit('http://localhost:8090');
21 |
22 | cy.window().then((win) => {
23 | win.history.pushState({}, 'react16', `${basename}/react16/vm-sandbox`);
24 | cy.contains('[data-test=title]', ProxyVariableTitle)
25 | .then(() => {
26 | expect(win.history.scrollRestoration).to.equal('auto');
27 | })
28 | .then(() => {
29 | return cy.get('[data-test=click-set-history-proxy-variable]').click();
30 | })
31 | .then(() => {
32 | expect(win.history.scrollRestoration).to.equal('manual');
33 | });
34 | });
35 | });
36 | });
37 |
--------------------------------------------------------------------------------
/packages/bridge-react/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Bytedance Inc.
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/packages/bridge-vue-v2/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Bytedance Inc.
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/packages/bridge-vue-v3/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Bytedance Inc.
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/packages/browser-vm/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Bytedance Inc.
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/dev/app-angular/karma.conf.js:
--------------------------------------------------------------------------------
1 | // Karma configuration file, see link for more information
2 | // https://karma-runner.github.io/1.0/config/configuration-file.html
3 |
4 | module.exports = function (config) {
5 | config.set({
6 | basePath: '',
7 | frameworks: ['jasmine', '@angular-devkit/build-angular'],
8 | plugins: [
9 | require('karma-jasmine'),
10 | require('karma-chrome-launcher'),
11 | require('karma-jasmine-html-reporter'),
12 | require('karma-coverage-istanbul-reporter'),
13 | require('@angular-devkit/build-angular/plugins/karma'),
14 | ],
15 | client: {
16 | clearContext: false, // leave Jasmine Spec Runner output visible in browser
17 | },
18 | coverageIstanbulReporter: {
19 | dir: require('path').join(__dirname, './coverage/angular'),
20 | reports: ['html', 'lcovonly', 'text-summary'],
21 | fixWebpackSourcePaths: true,
22 | },
23 | reporters: ['progress', 'kjhtml'],
24 | port: 9876,
25 | colors: true,
26 | logLevel: config.LOG_INFO,
27 | autoWatch: true,
28 | browsers: ['Chrome'],
29 | singleRun: false,
30 | restartOnFileChange: true,
31 | });
32 | };
33 |
--------------------------------------------------------------------------------
/packages/bridge-react-v18/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Bytedance Inc.
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/packages/browser-snapshot/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Bytedance Inc.
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/dev/app-react-16/src/App.less:
--------------------------------------------------------------------------------
1 | @import '../node_modules/@arco-design/web-react/dist/css/index.less';
2 |
3 | @prefix: sub-app-react16;
4 |
5 | .@{prefix}-layout-content {
6 | .App {
7 | text-align: center;
8 | background-color: #282c34;
9 | font-size: 18px;
10 | overflow: hidden;
11 | color: white;
12 | }
13 |
14 | .App-logo {
15 | height: 200px;
16 | pointer-events: none;
17 | }
18 |
19 | .App ul {
20 | display: inline-block;
21 | list-style: none;
22 | }
23 |
24 | .App li {
25 | display: inline-block;
26 | list-style: none;
27 | padding: 10px;
28 | }
29 |
30 | .App a:visited {
31 | color: #61dafb;
32 | }
33 |
34 | .App a.tabActive {
35 | color: #7fffd4;
36 | }
37 |
38 | @media (prefers-reduced-motion: no-preference) {
39 | .App-logo {
40 | animation: App-logo-spin infinite 20s linear;
41 | }
42 | }
43 |
44 | .click-btn {
45 | color: coral;
46 | cursor: pointer;
47 | margin-top: 6px;
48 | }
49 |
50 | @keyframes App-logo-spin {
51 | from {
52 | transform: rotate(0deg);
53 | }
54 | to {
55 | transform: rotate(360deg);
56 | }
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/dev/app-react-18/src/App.less:
--------------------------------------------------------------------------------
1 | @import '../node_modules/@arco-design/web-react/dist/css/index.less';
2 |
3 | @prefix: sub-app-react16;
4 |
5 | .@{prefix}-layout-content {
6 | .App {
7 | text-align: center;
8 | background-color: #282c34;
9 | font-size: 18px;
10 | overflow: hidden;
11 | color: white;
12 | }
13 |
14 | .App-logo {
15 | height: 200px;
16 | pointer-events: none;
17 | }
18 |
19 | .App ul {
20 | display: inline-block;
21 | list-style: none;
22 | }
23 |
24 | .App li {
25 | display: inline-block;
26 | list-style: none;
27 | padding: 10px;
28 | }
29 |
30 | .App a:visited {
31 | color: #61dafb;
32 | }
33 |
34 | .App a.active {
35 | color: #7fffd4;
36 | }
37 |
38 | @media (prefers-reduced-motion: no-preference) {
39 | .App-logo {
40 | animation: App-logo-spin infinite 20s linear;
41 | }
42 | }
43 |
44 | .click-btn {
45 | color: coral;
46 | cursor: pointer;
47 | margin-top: 6px;
48 | }
49 |
50 | @keyframes App-logo-spin {
51 | from {
52 | transform: rotate(0deg);
53 | }
54 | to {
55 | transform: rotate(360deg);
56 | }
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/packages/remote-module/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Bytedance Inc.
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 |
24 |
--------------------------------------------------------------------------------
/dev/app-angular/src/app/app.component.spec.ts:
--------------------------------------------------------------------------------
1 | import { TestBed } from '@angular/core/testing';
2 | import { RouterTestingModule } from '@angular/router/testing';
3 | import { AppComponent } from './app.component';
4 |
5 | describe('AppComponent', () => {
6 | beforeEach(async () => {
7 | await TestBed.configureTestingModule({
8 | imports: [RouterTestingModule],
9 | declarations: [AppComponent],
10 | }).compileComponents();
11 | });
12 |
13 | it('should create the app', () => {
14 | const fixture = TestBed.createComponent(AppComponent);
15 | const app = fixture.componentInstance;
16 | expect(app).toBeTruthy();
17 | });
18 |
19 | it(`should have as title 'angular'`, () => {
20 | const fixture = TestBed.createComponent(AppComponent);
21 | const app = fixture.componentInstance;
22 | expect(app.title).toEqual('angular');
23 | });
24 |
25 | it('should render title', () => {
26 | const fixture = TestBed.createComponent(AppComponent);
27 | fixture.detectChanges();
28 | const compiled = fixture.nativeElement;
29 | expect(compiled.querySelector('.content span').textContent).toContain(
30 | 'angular app is running!',
31 | );
32 | });
33 | });
34 |
--------------------------------------------------------------------------------
/packages/browser-vm/src/types.ts:
--------------------------------------------------------------------------------
1 | import { Sandbox } from './sandbox';
2 | import type { Node } from '@garfish/utils';
3 | import type { LoaderOptions } from '@garfish/loader';
4 |
5 | export type FakeWindow = Window & Record;
6 | export type Module = (sandbox: Sandbox) => OverridesData | void;
7 |
8 | export interface OverridesData {
9 | recover?: () => void;
10 | prepare?: () => void;
11 | created?: (context: Sandbox['global']) => void;
12 | override?: Record;
13 | }
14 | export interface ReplaceGlobalVariables {
15 | recoverList: Array;
16 | prepareList: Array;
17 | createdList: Array;
18 | overrideList: Record;
19 | }
20 |
21 | export interface SandboxOptions {
22 | namespace: string;
23 | baseUrl?: string;
24 | fixBaseUrl?: boolean;
25 | disableWith?: boolean;
26 | strictIsolation?: boolean;
27 | modules?: Array;
28 | sourceList?: Array<{ tagName: string; url: string }>;
29 | loaderOptions?: LoaderOptions;
30 | el?: () => Element | ShadowRoot | null;
31 | protectVariable?: () => Array;
32 | insulationVariable?: () => Array;
33 | }
34 |
--------------------------------------------------------------------------------
/dev/app-vue-2/src/store/store.js:
--------------------------------------------------------------------------------
1 | export default {
2 | state: {
3 | id: 1,
4 | todos: [{ id: 1, text: 'default todo', done: false }],
5 | basename: '',
6 | mainAppProps: {},
7 | },
8 |
9 | mutations: {
10 | done(state, id) {
11 | this.state.todos = this.state.todos.filter((item) => item.id !== id);
12 | },
13 | add(state, item) {
14 | state.id += 1;
15 | item.id = state.id;
16 | state.todos.push(item);
17 | },
18 | setProps(state, item) {
19 | state.mainAppProps = item;
20 | },
21 | setBasename(state, basename) {
22 | state.basename = basename;
23 | },
24 | },
25 |
26 | actions: {
27 | done(context, id) {
28 | context.commit('done', id);
29 | },
30 | add(context, item) {
31 | context.commit('add', item);
32 | },
33 | setProps(context, item) {
34 | context.commit('setProps', item);
35 | },
36 | setBasename(context, basename) {
37 | context.commit('setBasename', basename);
38 | },
39 | },
40 |
41 | getters: {
42 | doneTodos: (state) => {
43 | if (state.todos && state.todos.length > 0) {
44 | return state.todos.filter((todo) => todo.done);
45 | }
46 | },
47 | },
48 | };
49 |
--------------------------------------------------------------------------------
/packages/core/src/plugins/performance/index.ts:
--------------------------------------------------------------------------------
1 | import { getRenderNode } from '@garfish/utils';
2 | import { interfaces } from '../../index';
3 | import { SubAppObserver } from './subAppObserver';
4 |
5 | // Key nodes in Garfish corresponding to the life cycle of registration
6 | export function GarfishPerformance() {
7 | return function (): interfaces.Plugin {
8 | const subAppMap = {};
9 | return {
10 | name: 'performance',
11 |
12 | beforeLoad(appInfo) {
13 | if (!subAppMap[appInfo.name] && appInfo.domGetter) {
14 | subAppMap[appInfo.name] = new SubAppObserver({
15 | subAppRootSelector: appInfo.domGetter,
16 | });
17 | }
18 | subAppMap[appInfo.name].subAppBeforeLoad(appInfo.entry);
19 | },
20 |
21 | afterLoad(appInfo, appInstance: interfaces.App) {
22 | if (appInstance) {
23 | appInstance.appPerformance = subAppMap[appInfo.name] as any;
24 | }
25 | },
26 |
27 | beforeMount(appInfo) {
28 | subAppMap[appInfo.name].subAppBeforeMount(appInfo.entry);
29 | },
30 |
31 | beforeUnmount(appInfo) {
32 | subAppMap[appInfo.name].subAppUnmount(appInfo.entry);
33 | },
34 | };
35 | };
36 | }
37 |
--------------------------------------------------------------------------------
/packages/remote-module/src/actuator.ts:
--------------------------------------------------------------------------------
1 | import { evalWithEnv } from '@garfish/utils';
2 | import { ModuleManager } from '@garfish/loader';
3 | import { hooks } from './hooks';
4 | import { currentApp, moduleConfig } from './common';
5 |
6 | export class Actuator {
7 | private manager: ModuleManager;
8 | public env: Record;
9 |
10 | constructor(manager: ModuleManager, externals?: Record) {
11 | this.manager = manager;
12 | this.env = {
13 | exports: {},
14 | module: null,
15 | require: (key) =>
16 | (externals || {})[key] ||
17 | (moduleConfig.externals && moduleConfig.externals[key]) ||
18 | currentApp?.context?.externals[key],
19 | };
20 | this.env.module = this.env;
21 | hooks.lifecycle.initModule.emit(this);
22 | }
23 |
24 | execScript() {
25 | const { url, moduleCode } = this.manager;
26 | if (currentApp) {
27 | // Avoid conflict with Garfish cjs
28 | currentApp.execScript(moduleCode, this.env, url, { noEntry: true });
29 | } else {
30 | const sourceUrl = `\n${url ? `//# sourceURL=${url}\n` : ''}`;
31 | evalWithEnv(`;${moduleCode}\n${sourceUrl}`, this.env, window);
32 | }
33 | return this.env;
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/dev/app-react-16/src/index.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import { reactBridge } from '@garfish/bridge-react';
4 | import RootComponent from './root';
5 | import ErrorBoundary from './ErrorBoundary';
6 |
7 | // 在首次加载和执行时会触发该函数
8 | // export const provider = (props) => {
9 | // const root = props.dom
10 | // ? props.dom.querySelector("#root")
11 | // : document.querySelector("#root");
12 |
13 | // return {
14 | // render() {
15 | // ReactDOM.render(, root);
16 | // },
17 | // destroy({ dom }) {
18 | // ReactDOM.unmountComponentAtNode(
19 | // dom ? dom.querySelector("#root") : document.querySelector("#root")
20 | // );
21 | // },
22 | // };
23 | // };
24 |
25 | export const provider = reactBridge({
26 | el: '#root',
27 | rootComponent: RootComponent,
28 | errorBoundary: () => ,
29 | });
30 |
31 | // 这能够让子应用独立运行起来,以保证后续子应用能脱离主应用独立运行,方便调试、开发
32 | if (!window.__GARFISH__) {
33 | ReactDOM.render(
34 | ,
39 | document.querySelector('#root'),
40 | );
41 | }
42 |
--------------------------------------------------------------------------------
/packages/router/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@garfish/router",
3 | "version": "1.8.2",
4 | "description": "router module.",
5 | "keywords": [
6 | "garfish",
7 | "router"
8 | ],
9 | "author": "zhouxiao ",
10 | "homepage": "http://garfish.bytedance.com",
11 | "license": "MIT",
12 | "repository": {
13 | "type": "git",
14 | "url": "git+https://github.com/bytedance/garfish.git"
15 | },
16 | "bugs": {
17 | "url": "https://github.com/bytedance/garfish/issues"
18 | },
19 | "exports": {
20 | ".": {
21 | "import": "./dist/esm/index.js",
22 | "require": "./dist/index.js"
23 | },
24 | "./*": "./*"
25 | },
26 | "main": "dist/index.js",
27 | "module": "dist/esm/index.js",
28 | "types": "./src/index.ts",
29 | "scripts": {
30 | "build": "rimraf dist && tsup src/index.ts",
31 | "dev": "cross-env WATCH=true tsup src/index.ts"
32 | },
33 | "dependencies": {
34 | "@garfish/core": "workspace:*",
35 | "@garfish/utils": "workspace:*"
36 | },
37 | "publishConfig": {
38 | "registry": "https://registry.npmjs.org",
39 | "access": "public",
40 | "types": "./dist/index.d.ts"
41 | },
42 | "gitHead": "da33dd16bb9e99588f34079f8b961d0cf9f059fc"
43 | }
44 |
--------------------------------------------------------------------------------
/packages/loader/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@garfish/loader",
3 | "version": "1.8.2",
4 | "description": "loader module.",
5 | "keywords": [
6 | "garfish",
7 | "loader"
8 | ],
9 | "author": "chentao.arthur ",
10 | "homepage": "http://garfish.bytedance.com",
11 | "license": "MIT",
12 | "repository": {
13 | "type": "git",
14 | "url": "git+https://github.com/bytedance/garfish.git"
15 | },
16 | "bugs": {
17 | "url": "https://github.com/bytedance/garfish/issues"
18 | },
19 | "exports": {
20 | ".": {
21 | "import": "./dist/esm/index.js",
22 | "require": "./dist/index.js"
23 | },
24 | "./*": "./*"
25 | },
26 | "main": "dist/index.js",
27 | "module": "dist/esm/index.js",
28 | "types": "./src/index.ts",
29 | "scripts": {
30 | "build": "rimraf dist && tsup src/index.ts",
31 | "dev": "cross-env WATCH=true tsup src/index.ts"
32 | },
33 | "dependencies": {
34 | "@garfish/hooks": "workspace:*",
35 | "@garfish/utils": "workspace:*"
36 | },
37 | "publishConfig": {
38 | "registry": "https://registry.npmjs.org",
39 | "access": "public",
40 | "types": "./dist/index.d.ts"
41 | },
42 | "gitHead": "e8bf48ea8ca8db408a4a0a1cdab8ce4a50ab279b"
43 | }
44 |
--------------------------------------------------------------------------------
/packages/loader/src/utils.ts:
--------------------------------------------------------------------------------
1 | import { error, parseContentType } from '@garfish/utils';
2 | import { Manager, Loader } from './index';
3 |
4 | export async function request(url: string, config: RequestInit) {
5 | const result = await fetch(url, config || {});
6 | // Response codes greater than "400" are regarded as errors
7 | if (result.status >= 400) {
8 | error(`"${url}" load failed with status "${result.status}"`);
9 | }
10 | const code = await result.text();
11 | const type = result.headers.get('content-type') || '';
12 | const size = Number(result.headers.get('content-size'));
13 | const mimeType = parseContentType(type || '');
14 |
15 | return {
16 | code,
17 | result,
18 | mimeType,
19 | type,
20 | size: Number.isNaN(size) ? null : size,
21 | };
22 | }
23 |
24 | export function copyResult(result) {
25 | if (result.resourceManager) {
26 | result.resourceManager = (result.resourceManager as Manager).clone();
27 | }
28 | return result;
29 | }
30 |
31 | // Compatible with old api
32 | export function mergeConfig(loader: Loader, url: string) {
33 | const extra = loader.requestConfig;
34 | const config = typeof extra === 'function' ? extra(url) : extra;
35 | return { mode: 'cors', ...config } as RequestInit;
36 | }
37 |
--------------------------------------------------------------------------------