├── .github ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md └── workflows │ ├── nightly.yml │ ├── pr-title.yml │ ├── release-notes.yml │ ├── test-e2e-composable.yml │ ├── test-e2e-options.yml │ ├── test-e2e-ssr.yml │ └── test.yml ├── .gitignore ├── .test-todo ├── test-ssr-composition │ ├── .browserslistrc │ ├── .editorconfig │ ├── .gitignore │ ├── README.md │ ├── apollo-server │ │ ├── context.js │ │ ├── data-sources.js │ │ ├── directives.js │ │ ├── mocks.js │ │ ├── resolvers.js │ │ ├── schema.graphql │ │ ├── server.js │ │ ├── type-defs.js │ │ └── utils │ │ │ ├── db.js │ │ │ └── upload.js │ ├── apollo.config.js │ ├── babel.config.js │ ├── cypress.json │ ├── package.json │ ├── postcss.config.js │ ├── public │ │ ├── favicon.ico │ │ ├── index.html │ │ └── index.ssr.html │ ├── src │ │ ├── App.vue │ │ ├── assets │ │ │ └── logo.png │ │ ├── components │ │ │ ├── ApolloExample.vue │ │ │ ├── ApolloLoading.vue │ │ │ └── HelloWorld.vue │ │ ├── entry-client.js │ │ ├── entry-server.js │ │ ├── graphql │ │ │ ├── AddMessage.gql │ │ │ ├── FileFragment.gql │ │ │ ├── Files.gql │ │ │ ├── HelloWorld.gql │ │ │ ├── MessageAdded.gql │ │ │ ├── MessageFragment.gql │ │ │ ├── Messages.gql │ │ │ └── UploadFile.gql │ │ ├── main.js │ │ ├── router │ │ │ └── index.js │ │ ├── views │ │ │ ├── About.vue │ │ │ └── Home.vue │ │ └── vue-apollo.js │ ├── tests │ │ └── e2e │ │ │ ├── .eslintrc.js │ │ │ ├── plugins │ │ │ └── index.js │ │ │ ├── specs │ │ │ └── apollo-ssr.js │ │ │ └── support │ │ │ ├── commands.js │ │ │ └── index.js │ └── vue.config.js └── test-ssr │ ├── .browserslistrc │ ├── .editorconfig │ ├── .gitignore │ ├── README.md │ ├── apollo-server │ ├── context.js │ ├── data-sources.js │ ├── directives.js │ ├── mocks.js │ ├── resolvers.js │ ├── schema.graphql │ ├── server.js │ ├── type-defs.js │ └── utils │ │ ├── db.js │ │ └── upload.js │ ├── apollo.config.js │ ├── babel.config.js │ ├── cypress.json │ ├── package.json │ ├── postcss.config.js │ ├── public │ ├── favicon.ico │ ├── index.html │ └── index.ssr.html │ ├── src │ ├── App.vue │ ├── assets │ │ └── logo.png │ ├── components │ │ ├── ApolloExample.vue │ │ ├── ApolloLoading.vue │ │ └── HelloWorld.vue │ ├── entry-client.js │ ├── entry-server.js │ ├── graphql │ │ ├── AddMessage.gql │ │ ├── FileFragment.gql │ │ ├── Files.gql │ │ ├── HelloWorld.gql │ │ ├── MessageAdded.gql │ │ ├── MessageFragment.gql │ │ ├── Messages.gql │ │ └── UploadFile.gql │ ├── main.js │ ├── router │ │ └── index.js │ ├── views │ │ ├── About.vue │ │ └── Home.vue │ └── vue-apollo.js │ ├── tests │ └── e2e │ │ ├── .eslintrc.js │ │ ├── plugins │ │ └── index.js │ │ ├── specs │ │ └── apollo-ssr.js │ │ └── support │ │ ├── commands.js │ │ └── index.js │ └── vue.config.js ├── .vscode └── settings.json ├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── eslint.config.mjs ├── meow.eslintrc.js ├── package.json ├── packages ├── docs │ ├── package.json │ └── src │ │ ├── .vitepress │ │ ├── config.js │ │ └── theme │ │ │ ├── components │ │ │ └── SponsorButton.vue │ │ │ ├── index.js │ │ │ └── styles │ │ │ └── index.pcss │ │ ├── api │ │ ├── apollo-mutation.md │ │ ├── apollo-provider.md │ │ ├── apollo-query.md │ │ ├── apollo-subscribe-to-more.md │ │ ├── dollar-apollo.md │ │ ├── index.md │ │ ├── smart-query.md │ │ ├── smart-subscription.md │ │ ├── ssr.md │ │ ├── use-apollo-client.md │ │ ├── use-lazy-query.md │ │ ├── use-loading.md │ │ ├── use-mutation.md │ │ ├── use-query.md │ │ └── use-subscription.md │ │ ├── guide-advanced │ │ ├── index.md │ │ ├── local-state.md │ │ ├── ssr.md │ │ └── testing.md │ │ ├── guide-components │ │ ├── index.md │ │ ├── mutation.md │ │ ├── query.md │ │ ├── setup.md │ │ └── subscribe-to-more.md │ │ ├── guide-composable │ │ ├── cache-interaction.md │ │ ├── error-handling.md │ │ ├── fragments.md │ │ ├── index.md │ │ ├── mutation.md │ │ ├── pagination.md │ │ ├── query.md │ │ ├── setup.md │ │ └── subscription.md │ │ ├── guide-option │ │ ├── index.md │ │ ├── multiple-clients.md │ │ ├── mutations.md │ │ ├── pagination.md │ │ ├── queries.md │ │ ├── setup.md │ │ ├── special-options.md │ │ ├── subscriptions.md │ │ └── usage.md │ │ ├── guide │ │ ├── index.md │ │ └── installation.md │ │ ├── index.md │ │ ├── migration │ │ └── index.md │ │ ├── public │ │ ├── error-log.jpeg │ │ ├── favicon.png │ │ ├── hero.svg │ │ ├── logo.svg │ │ └── vue-apollo-graphql.png │ │ └── zh-cn │ │ ├── api │ │ ├── apollo-mutation.md │ │ ├── apollo-provider.md │ │ ├── apollo-query.md │ │ ├── apollo-subscribe-to-more.md │ │ ├── dollar-apollo.md │ │ ├── index.md │ │ ├── smart-query.md │ │ ├── smart-subscription.md │ │ ├── ssr.md │ │ ├── use-apollo-client.md │ │ ├── use-loading.md │ │ ├── use-mutation.md │ │ ├── use-query.md │ │ └── use-subscription.md │ │ ├── guide-advanced │ │ ├── index.md │ │ ├── local-state.md │ │ ├── ssr.md │ │ └── testing.md │ │ ├── guide-components │ │ ├── index.md │ │ ├── mutation.md │ │ ├── query.md │ │ ├── setup.md │ │ └── subscribe-to-more.md │ │ ├── guide-composable │ │ ├── cache-interaction.md │ │ ├── error-handling.md │ │ ├── fragments.md │ │ ├── index.md │ │ ├── mutation.md │ │ ├── pagination.md │ │ ├── query.md │ │ ├── setup.md │ │ └── subscription.md │ │ ├── guide-option │ │ ├── index.md │ │ ├── multiple-clients.md │ │ ├── mutations.md │ │ ├── pagination.md │ │ ├── queries.md │ │ ├── setup.md │ │ ├── special-options.md │ │ ├── subscriptions.md │ │ └── usage.md │ │ ├── guide │ │ ├── index.md │ │ └── installation.md │ │ ├── index.md │ │ └── migration │ │ └── index.md ├── test-e2e-composable-vue3 │ ├── .browserslistrc │ ├── .editorconfig │ ├── .gitignore │ ├── README.md │ ├── cypress.config.ts │ ├── index.html │ ├── package.json │ ├── postcss.config.js │ ├── src │ │ ├── apollo.ts │ │ ├── assets │ │ │ └── styles │ │ │ │ └── tailwind.css │ │ ├── components │ │ │ ├── App.vue │ │ │ ├── ChannelList.vue │ │ │ ├── ChannelListPinia.vue │ │ │ ├── ChannelListPinia2.vue │ │ │ ├── ChannelListPiniaContainer.vue │ │ │ ├── ChannelView.vue │ │ │ ├── Disabled.vue │ │ │ ├── GlobalLoading.vue │ │ │ ├── KeepPreviousResult.vue │ │ │ ├── LazyQuery.vue │ │ │ ├── LazyQueryImmediately.vue │ │ │ ├── LazyQueryLoad.vue │ │ │ ├── LazyQueryLoadError.vue │ │ │ ├── MessageForm.vue │ │ │ ├── MessageItem.vue │ │ │ ├── NoSetupQuery.vue │ │ │ ├── NoSetupQueryMultiClient.vue │ │ │ ├── NoSetupScopeQuery.vue │ │ │ ├── NullQuery.vue │ │ │ ├── OnResult.vue │ │ │ ├── OnResultChild.vue │ │ │ ├── PartialError.vue │ │ │ ├── Subscription.vue │ │ │ ├── Subscriptions.vue │ │ │ ├── UpdateQuery.vue │ │ │ └── Welcome.vue │ │ ├── main.ts │ │ ├── router.ts │ │ ├── shims-vue.d.ts │ │ └── stores │ │ │ └── channel.ts │ ├── tailwind.config.js │ ├── tests │ │ └── e2e │ │ │ ├── .eslintrc.js │ │ │ ├── specs │ │ │ ├── errorPolicy.cy.ts │ │ │ ├── keepPreviousResult.cy.ts │ │ │ ├── lazy.cy.ts │ │ │ ├── nullableQuery.cy.ts │ │ │ ├── outsideComponent.cy.ts │ │ │ ├── pinia.cy.ts │ │ │ ├── subscription.cy.ts │ │ │ ├── test.cy.ts │ │ │ └── updateQuery.cy.ts │ │ │ └── support │ │ │ ├── commands.ts │ │ │ └── index.ts │ ├── tsconfig.json │ └── vite.config.ts ├── test-e2e-ssr │ ├── .browserslistrc │ ├── .editorconfig │ ├── .gitignore │ ├── README.md │ ├── cypress.config.ts │ ├── index.html │ ├── package.json │ ├── postcss.config.js │ ├── server.mjs │ ├── src │ │ ├── apollo.ts │ │ ├── app.ts │ │ ├── assets │ │ │ └── styles │ │ │ │ └── tailwind.css │ │ ├── components │ │ │ ├── App.vue │ │ │ ├── ChannelList.vue │ │ │ ├── ChannelView.vue │ │ │ ├── ClientOnly.vue │ │ │ ├── GlobalLoading.vue │ │ │ ├── LazyQuery.vue │ │ │ ├── LazyQueryImmediately.vue │ │ │ ├── MessageForm.vue │ │ │ ├── MessageItem.vue │ │ │ └── Welcome.vue │ │ ├── context.ts │ │ ├── entry-client.ts │ │ ├── entry-server.ts │ │ ├── env.ts │ │ ├── router.ts │ │ └── shims-vue.d.ts │ ├── tailwind.config.js │ ├── tests │ │ └── e2e │ │ │ ├── .eslintrc.js │ │ │ ├── specs │ │ │ └── test.cy.ts │ │ │ └── support │ │ │ ├── commands.ts │ │ │ └── index.ts │ ├── tsconfig.json │ └── vite.config.ts ├── test-e2e │ ├── .gitignore │ ├── .graphqlconfig.yml │ ├── .postcssrc.js │ ├── README.md │ ├── apollo-server │ │ ├── connectors │ │ │ ├── channels.js │ │ │ ├── messages.js │ │ │ └── users.js │ │ ├── context.js │ │ ├── directives.js │ │ ├── directives │ │ │ └── private.js │ │ ├── reset.js │ │ ├── resolvers.js │ │ ├── schema.graphql │ │ ├── triggers.js │ │ └── type-defs.js │ ├── babel.config.js │ ├── cypress.config.ts │ ├── package.json │ ├── public │ │ ├── favicon.ico │ │ └── index.html │ ├── server.js │ ├── src │ │ ├── App.vue │ │ ├── components │ │ │ ├── ChannelList.vue │ │ │ ├── ChannelView.vue │ │ │ ├── ManualAddSmartQuery.vue │ │ │ ├── MessageForm.vue │ │ │ ├── MessageItem.vue │ │ │ ├── MockSendMessage.vue │ │ │ ├── PartialError.vue │ │ │ ├── UpdateCache.vue │ │ │ ├── UserCurrent.vue │ │ │ ├── UserLogin.vue │ │ │ └── WelcomeView.vue │ │ ├── graphql │ │ │ ├── channel.gql │ │ │ ├── channelFragment.gql │ │ │ ├── channels.gql │ │ │ ├── messageAdd.gql │ │ │ ├── messageChanged.gql │ │ │ ├── messageFragment.gql │ │ │ ├── messageRemove.gql │ │ │ ├── messageUpdate.gql │ │ │ ├── userCurrent.gql │ │ │ ├── userFragment.gql │ │ │ ├── userLogin.gql │ │ │ ├── userLogout.gql │ │ │ └── userRegister.gql │ │ ├── main.js │ │ ├── mixins │ │ │ └── UserCurrent.js │ │ ├── router.js │ │ ├── store.js │ │ ├── style │ │ │ └── imports.styl │ │ └── vue-apollo.js │ ├── tests │ │ └── e2e │ │ │ ├── .eslintrc │ │ │ ├── specs │ │ │ ├── cache.cy.js │ │ │ ├── chat.cy.js │ │ │ ├── errorPolicy.cy.js │ │ │ └── manual-smart-query.cy.js │ │ │ └── support │ │ │ ├── commands.js │ │ │ └── index.js │ └── vue.config.js ├── test-server │ ├── bin.mjs │ ├── package.json │ ├── src │ │ ├── data.ts │ │ ├── index.ts │ │ ├── schema.ts │ │ └── util.ts │ └── tsconfig.json ├── vue-apollo-components │ ├── .npmignore │ ├── README.md │ ├── babel.config.js │ ├── build │ │ ├── rollup.config.base.js │ │ ├── rollup.config.browser.js │ │ ├── rollup.config.es.js │ │ └── rollup.config.umd.js │ ├── package.json │ └── src │ │ ├── ApolloMutation.js │ │ ├── ApolloQuery.js │ │ ├── ApolloSubscribeToMore.js │ │ └── index.js ├── vue-apollo-composable │ ├── README.md │ ├── esbuild.mjs │ ├── package.json │ ├── src │ │ ├── index.ts │ │ ├── useApolloClient.ts │ │ ├── useLazyQuery.ts │ │ ├── useLoading.ts │ │ ├── useMutation.ts │ │ ├── useQuery.ts │ │ ├── useResult.ts │ │ ├── useSubscription.ts │ │ └── util │ │ │ ├── ExtractSingleKey.ts │ │ │ ├── ReactiveFunction.ts │ │ │ ├── env.ts │ │ │ ├── loadingTracking.ts │ │ │ ├── paramToReactive.ts │ │ │ ├── paramToRef.ts │ │ │ ├── toApolloError.ts │ │ │ └── useEventHook.ts │ ├── tests │ │ ├── .eslintrc.js │ │ ├── fixtures │ │ │ └── graphql-example-types.ts │ │ └── types │ │ │ ├── assertions.ts │ │ │ ├── tsconfig.json │ │ │ ├── useApolloClient-types.test.ts │ │ │ ├── useLoading-types.test.ts │ │ │ ├── useMutation-types.test.ts │ │ │ ├── useQuery-types.test.ts │ │ │ ├── useResult-types.test.ts │ │ │ ├── useSubscription-types.test.ts │ │ │ └── util │ │ │ └── ExtractSingleKey.test.ts │ ├── tsconfig.json │ └── tsconfig.lint.json ├── vue-apollo-option │ ├── .npmignore │ ├── README.md │ ├── babel.config.js │ ├── build │ │ ├── rollup.config.base.js │ │ ├── rollup.config.browser.js │ │ ├── rollup.config.es.js │ │ └── rollup.config.umd.js │ ├── lib │ │ ├── consts.js │ │ └── utils.js │ ├── package.json │ ├── src │ │ ├── apollo-provider.js │ │ ├── dollar-apollo.js │ │ ├── env.js │ │ ├── index.js │ │ ├── mixin.js │ │ ├── smart-apollo.js │ │ ├── smart-query.js │ │ └── smart-subscription.js │ ├── tests │ │ └── unit │ │ │ ├── .eslintrc.js │ │ │ └── ssr.test.js │ ├── types │ │ ├── .gitignore │ │ ├── apollo-provider.d.ts │ │ ├── index.d.ts │ │ ├── options.d.ts │ │ ├── test │ │ │ ├── App.ts │ │ │ ├── App.vue │ │ │ ├── Decorator.ts │ │ │ ├── index.ts │ │ │ └── tsconfig.json │ │ ├── utils.d.ts │ │ ├── vue-apollo.d.ts │ │ └── vue.d.ts │ └── vitest.config.ts ├── vue-apollo-ssr │ ├── README.md │ ├── build.mjs │ ├── package.json │ ├── src │ │ └── index.ts │ └── tsconfig.json └── vue-apollo-util │ ├── README.md │ ├── package.json │ ├── src │ ├── errorLog.ts │ └── index.ts │ └── tsconfig.json ├── pnpm-lock.yaml ├── pnpm-workspace.yaml └── postcss.config.js /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: Akryum 4 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: need team repro 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Versions** 24 | vue: 25 | vue-apollo: 26 | @apollo/client: 27 | 28 | **Additional context** 29 | Add any other context about the problem here. 30 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: enhancement 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/workflows/nightly.yml: -------------------------------------------------------------------------------- 1 | name: Publish Nightlies 2 | on: 3 | pull_request: 4 | push: 5 | branches: 6 | - '**' 7 | tags: 8 | - '!**' 9 | 10 | jobs: 11 | build: 12 | runs-on: ubuntu-latest 13 | 14 | steps: 15 | - name: Set alternate npm integrity keys 16 | run: | 17 | echo COREPACK_INTEGRITY_KEYS="$(curl https://registry.npmjs.org/-/npm/v1/keys | jq -c '{npm: .keys}')" >> $GITHUB_ENV 18 | - uses: actions/checkout@v4 19 | - run: corepack enable 20 | - uses: actions/setup-node@v4 21 | with: 22 | node-version: 23 23 | cache: pnpm 24 | - run: pnpm install 25 | 26 | - name: Build 27 | run: pnpm build 28 | 29 | - run: pnpx pkg-pr-new publish './packages/*' 30 | -------------------------------------------------------------------------------- /.github/workflows/pr-title.yml: -------------------------------------------------------------------------------- 1 | name: Check PR title 2 | 3 | on: 4 | pull_request_target: 5 | types: 6 | - opened 7 | - edited 8 | - synchronize 9 | 10 | jobs: 11 | check-pr-title: 12 | runs-on: ubuntu-latest 13 | name: Check PR title 14 | steps: 15 | # Please look up the latest version from 16 | # https://github.com/amannn/action-semantic-pull-request/releases 17 | - uses: amannn/action-semantic-pull-request@v3.4.2 18 | env: 19 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 20 | -------------------------------------------------------------------------------- /.github/workflows/release-notes.yml: -------------------------------------------------------------------------------- 1 | name: Create release 2 | 3 | on: 4 | push: 5 | tags: 6 | - 'v*' # Push events to matching v*, i.e. v1.0, v20.15.10 7 | 8 | jobs: 9 | build: 10 | name: Create Release 11 | runs-on: ubuntu-latest 12 | steps: 13 | - name: Checkout code 14 | uses: actions/checkout@master 15 | with: 16 | fetch-depth: 0 # Fetch all tags 17 | 18 | - name: Create Release for Tag 19 | id: release_tag 20 | uses: Akryum/release-tag@v4.0.7 21 | env: 22 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 23 | with: 24 | tag_name: ${{ github.ref }} 25 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Main continuous tests 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | - v4 8 | - feat/* 9 | - fix/* 10 | pull_request: 11 | workflow_dispatch: 12 | 13 | concurrency: 14 | group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} 15 | cancel-in-progress: true 16 | 17 | jobs: 18 | build-and-test: 19 | runs-on: ubuntu-latest 20 | name: Build and test 21 | 22 | steps: 23 | - name: Set alternate npm integrity keys 24 | run: | 25 | echo COREPACK_INTEGRITY_KEYS="$(curl https://registry.npmjs.org/-/npm/v1/keys | jq -c '{npm: .keys}')" >> $GITHUB_ENV 26 | - uses: actions/checkout@v4 27 | - run: corepack enable 28 | - uses: actions/setup-node@v4 29 | with: 30 | node-version: 23 31 | cache: pnpm 32 | - run: pnpm install 33 | 34 | - name: Lint 35 | run: pnpm run lint 36 | 37 | - name: Build 38 | run: pnpm run build 39 | 40 | - name: Types 41 | run: pnpm run test:types 42 | 43 | - name: Unit tests 44 | run: pnpm run test:unit 45 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | node_modules/ 3 | dist/ 4 | cache/ 5 | .eslintcache 6 | -------------------------------------------------------------------------------- /.test-todo/test-ssr-composition/.browserslistrc: -------------------------------------------------------------------------------- 1 | > 1% 2 | last 2 versions 3 | -------------------------------------------------------------------------------- /.test-todo/test-ssr-composition/.editorconfig: -------------------------------------------------------------------------------- 1 | [*.{js,jsx,ts,tsx,vue}] 2 | indent_style = space 3 | indent_size = 2 4 | trim_trailing_whitespace = true 5 | insert_final_newline = true 6 | -------------------------------------------------------------------------------- /.test-todo/test-ssr-composition/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | 5 | /tests/e2e/videos/ 6 | /tests/e2e/screenshots/ 7 | 8 | # local env files 9 | .env.local 10 | .env.*.local 11 | 12 | # Log files 13 | npm-debug.log* 14 | yarn-debug.log* 15 | yarn-error.log* 16 | 17 | # Editor directories and files 18 | .idea 19 | .vscode 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | 26 | /live/ 27 | -------------------------------------------------------------------------------- /.test-todo/test-ssr-composition/README.md: -------------------------------------------------------------------------------- 1 | # ssr 2 | 3 | ## Project setup 4 | ``` 5 | yarn install 6 | ``` 7 | 8 | ### Compiles and hot-reloads for development 9 | ``` 10 | yarn serve 11 | ``` 12 | 13 | ### Compiles and minifies for production 14 | ``` 15 | yarn build 16 | ``` 17 | 18 | ### Run your end-to-end tests 19 | ``` 20 | yarn test:e2e 21 | ``` 22 | 23 | ### Customize configuration 24 | See [Configuration Reference](https://cli.vuejs.org/config/). 25 | -------------------------------------------------------------------------------- /.test-todo/test-ssr-composition/apollo-server/context.js: -------------------------------------------------------------------------------- 1 | import { db } from './utils/db' 2 | import { processUpload } from './utils/upload' 3 | 4 | // Context passed to all resolvers (third argument) 5 | // req => Query 6 | // connection => Subscription 7 | // eslint-disable-next-line no-unused-vars 8 | export default ({ req, connection }) => { 9 | return { 10 | db, 11 | processUpload, 12 | 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /.test-todo/test-ssr-composition/apollo-server/data-sources.js: -------------------------------------------------------------------------------- 1 | export default function () { 2 | return {} 3 | } 4 | -------------------------------------------------------------------------------- /.test-todo/test-ssr-composition/apollo-server/directives.js: -------------------------------------------------------------------------------- 1 | export default { 2 | // Schema directives 3 | // https://www.apollographql.com/docs/graphql-tools/schema-directives.html 4 | } 5 | -------------------------------------------------------------------------------- /.test-todo/test-ssr-composition/apollo-server/mocks.js: -------------------------------------------------------------------------------- 1 | // Enable mocking in vue.config.js with `"pluginOptions": { "enableMocks": true }` 2 | // Customize mocking: https://www.apollographql.com/docs/graphql-tools/mocking.html#Customizing-mocks 3 | export default { 4 | // Mock resolvers here 5 | } 6 | -------------------------------------------------------------------------------- /.test-todo/test-ssr-composition/apollo-server/schema.graphql: -------------------------------------------------------------------------------- 1 | "Included scalars" 2 | scalar JSON 3 | scalar Upload 4 | 5 | "It will increment!" 6 | type Counter { 7 | "Number of increments" 8 | count: Int! 9 | "Full message for testing" 10 | countStr: String 11 | } 12 | 13 | "A text message send by users" 14 | type Message { 15 | id: ID! 16 | "Message content" 17 | text: String! 18 | } 19 | 20 | "Input from user to create a message" 21 | input MessageInput { 22 | "Message content" 23 | text: String! 24 | } 25 | 26 | type File { 27 | id: ID! 28 | path: String! 29 | filename: String! 30 | mimetype: String! 31 | encoding: String! 32 | } 33 | 34 | 35 | type Query { 36 | "Test query with a parameter" 37 | hello(name: String): String! 38 | "List of messages sent by users" 39 | messages: [Message] 40 | uploads: [File] 41 | 42 | } 43 | 44 | type Mutation { 45 | myMutation: String! 46 | "Add a message and publish it on 'messages' subscription channel" 47 | addMessage (input: MessageInput!): Message! 48 | singleUpload (file: Upload!): File! 49 | multipleUpload (files: [Upload!]!): [File!]! 50 | 51 | } 52 | 53 | type Subscription { 54 | mySub: String! 55 | "This will update every 2 seconds" 56 | counter: Counter! 57 | "When a new message is added" 58 | messageAdded: Message! 59 | 60 | } 61 | -------------------------------------------------------------------------------- /.test-todo/test-ssr-composition/apollo-server/server.js: -------------------------------------------------------------------------------- 1 | import ssrMiddleware from '@akryum/vue-cli-plugin-ssr/lib/app' 2 | import path from 'path' 3 | import express from 'express' 4 | 5 | export default app => { 6 | app.use('/files', express.static(path.resolve(__dirname, '../live/uploads'))) 7 | 8 | ssrMiddleware(app, { prodOnly: true }) 9 | } 10 | -------------------------------------------------------------------------------- /.test-todo/test-ssr-composition/apollo-server/type-defs.js: -------------------------------------------------------------------------------- 1 | import fs from 'fs' 2 | import path from 'path' 3 | 4 | export default fs.readFileSync(path.resolve(__dirname, './schema.graphql'), { encoding: 'utf8' }) 5 | -------------------------------------------------------------------------------- /.test-todo/test-ssr-composition/apollo-server/utils/db.js: -------------------------------------------------------------------------------- 1 | import Lowdb from 'lowdb' 2 | // import FileSync from 'lowdb/adapters/FileSync' 3 | import Memory from 'lowdb/adapters/Memory' 4 | import mkdirp from 'mkdirp' 5 | import { resolve } from 'path' 6 | 7 | mkdirp(resolve(__dirname, '../../live')) 8 | 9 | // export const db = new Lowdb(new FileSync(resolve(__dirname, '../../live/db.json'))) 10 | export const db = new Lowdb(new Memory()) 11 | 12 | // Seed an empty DB 13 | db.defaults({ 14 | messages: [ 15 | { 16 | id: 'a', 17 | text: 'Message 1', 18 | }, 19 | { 20 | id: 'b', 21 | text: 'Message 2', 22 | }, 23 | { 24 | id: 'c', 25 | text: 'Message 3', 26 | }, 27 | ], 28 | uploads: [], 29 | }).write() 30 | -------------------------------------------------------------------------------- /.test-todo/test-ssr-composition/apollo-server/utils/upload.js: -------------------------------------------------------------------------------- 1 | import { createWriteStream } from 'fs' 2 | import { resolve } from 'path' 3 | import { sync } from 'mkdirp' 4 | import { generate } from 'shortid' 5 | import { db } from './db' 6 | 7 | const uploadDir = resolve(__dirname, '../../live/uploads') 8 | 9 | // Ensure upload directory exists 10 | sync(uploadDir) 11 | 12 | const storeUpload = async ({ stream, filename }) => { 13 | const id = generate() 14 | const file = `${id}-${filename}` 15 | const path = `${uploadDir}/${file}` 16 | const urlPath = `files/${file}` 17 | 18 | return new Promise((resolve, reject) => 19 | stream 20 | .pipe(createWriteStream(path)) 21 | .on('finish', () => resolve({ id, path: urlPath })) 22 | .on('error', reject), 23 | ) 24 | } 25 | 26 | const recordFile = file => 27 | db 28 | .get('uploads') 29 | .push(file) 30 | .last() 31 | .write() 32 | 33 | export async function processUpload (file) { 34 | const { stream, filename, mimetype, encoding } = await file 35 | const { id, path } = await storeUpload({ stream, filename }) 36 | return recordFile({ id, filename, mimetype, encoding, path }) 37 | } 38 | -------------------------------------------------------------------------------- /.test-todo/test-ssr-composition/apollo.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | 3 | // Load .env files 4 | const { loadEnv } = require('vue-cli-plugin-apollo/utils/load-env') 5 | const env = loadEnv([ 6 | path.resolve(__dirname, '.env'), 7 | path.resolve(__dirname, '.env.local'), 8 | ]) 9 | 10 | module.exports = { 11 | client: { 12 | service: env.VUE_APP_APOLLO_ENGINE_SERVICE, 13 | includes: ['src/**/*.{js,jsx,ts,tsx,vue,gql}'], 14 | }, 15 | service: { 16 | name: env.VUE_APP_APOLLO_ENGINE_SERVICE, 17 | localSchemaFile: path.resolve(__dirname, './node_modules/.temp/graphql/schema.json'), 18 | }, 19 | engine: { 20 | endpoint: process.env.APOLLO_ENGINE_API_ENDPOINT, 21 | apiKey: env.VUE_APP_APOLLO_ENGINE_KEY, 22 | }, 23 | } 24 | -------------------------------------------------------------------------------- /.test-todo/test-ssr-composition/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | '@vue/cli-plugin-babel/preset', 4 | ], 5 | } 6 | -------------------------------------------------------------------------------- /.test-todo/test-ssr-composition/cypress.json: -------------------------------------------------------------------------------- 1 | { 2 | "pluginsFile": "tests/e2e/plugins/index.js" 3 | } 4 | -------------------------------------------------------------------------------- /.test-todo/test-ssr-composition/postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | autoprefixer: {}, 4 | }, 5 | } 6 | -------------------------------------------------------------------------------- /.test-todo/test-ssr-composition/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuejs/apollo/fb027e6adf4d4129fb26f8c918060771a0afd59b/.test-todo/test-ssr-composition/public/favicon.ico -------------------------------------------------------------------------------- /.test-todo/test-ssr-composition/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | ssr 9 | 10 | 11 | 14 |
15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /.test-todo/test-ssr-composition/public/index.ssr.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | {{ title }} 9 | {{{ renderResourceHints() }}} 10 | {{{ renderStyles() }}} 11 | 12 | 13 | 14 | {{{ renderState() }}} 15 | {{{ renderState({ contextKey: 'apolloState', windowKey: '__APOLLO_STATE__' }) }}} 16 | {{{ renderScripts() }}} 17 | 18 | 19 | -------------------------------------------------------------------------------- /.test-todo/test-ssr-composition/src/App.vue: -------------------------------------------------------------------------------- 1 | 24 | 25 | 42 | 43 | 74 | -------------------------------------------------------------------------------- /.test-todo/test-ssr-composition/src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuejs/apollo/fb027e6adf4d4129fb26f8c918060771a0afd59b/.test-todo/test-ssr-composition/src/assets/logo.png -------------------------------------------------------------------------------- /.test-todo/test-ssr-composition/src/components/ApolloLoading.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 29 | -------------------------------------------------------------------------------- /.test-todo/test-ssr-composition/src/components/HelloWorld.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 32 | -------------------------------------------------------------------------------- /.test-todo/test-ssr-composition/src/entry-client.js: -------------------------------------------------------------------------------- 1 | import 'isomorphic-fetch' 2 | import { loadAsyncComponents } from '@akryum/vue-cli-plugin-ssr/client' 3 | 4 | import { createApp } from './main' 5 | 6 | createApp({ 7 | async beforeApp ({ 8 | router, 9 | }) { 10 | await loadAsyncComponents({ router }) 11 | }, 12 | 13 | afterApp ({ 14 | app, 15 | router, 16 | }) { 17 | router.onReady(() => { 18 | app.$mount('#app') 19 | }) 20 | }, 21 | }) 22 | -------------------------------------------------------------------------------- /.test-todo/test-ssr-composition/src/entry-server.js: -------------------------------------------------------------------------------- 1 | import 'isomorphic-fetch' 2 | import * as ApolloSSR from '@vue/apollo-ssr' 3 | import { createApp } from './main' 4 | 5 | const prepareUrlForRouting = url => { 6 | const { BASE_URL } = process.env 7 | return url.startsWith(BASE_URL.replace(/\/$/, '')) 8 | ? url.slice(BASE_URL.length) 9 | : url 10 | } 11 | 12 | export default context => { 13 | return new Promise(async (resolve, reject) => { 14 | const { 15 | app, 16 | router, 17 | apolloClient, 18 | } = await createApp() 19 | 20 | router.push(prepareUrlForRouting(context.url)) 21 | 22 | router.onReady(() => { 23 | context.rendered = () => { 24 | // Same for Apollo client cache 25 | context.apolloState = ApolloSSR.getStates({ 26 | defaultClient: apolloClient, 27 | }) 28 | } 29 | resolve(app) 30 | }, reject) 31 | }) 32 | } 33 | -------------------------------------------------------------------------------- /.test-todo/test-ssr-composition/src/graphql/AddMessage.gql: -------------------------------------------------------------------------------- 1 | #import "./MessageFragment.gql" 2 | 3 | mutation addMessage ($input: MessageInput!) { 4 | addMessage (input: $input) { 5 | ...Message 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /.test-todo/test-ssr-composition/src/graphql/FileFragment.gql: -------------------------------------------------------------------------------- 1 | fragment file on File { 2 | id 3 | path 4 | filename 5 | mimetype 6 | encoding 7 | } 8 | -------------------------------------------------------------------------------- /.test-todo/test-ssr-composition/src/graphql/Files.gql: -------------------------------------------------------------------------------- 1 | #import "./FileFragment.gql" 2 | 3 | query files { 4 | files: uploads { 5 | ...file 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /.test-todo/test-ssr-composition/src/graphql/HelloWorld.gql: -------------------------------------------------------------------------------- 1 | query HelloWorld ($name: String) { 2 | hello (name: $name) 3 | } 4 | -------------------------------------------------------------------------------- /.test-todo/test-ssr-composition/src/graphql/MessageAdded.gql: -------------------------------------------------------------------------------- 1 | #import "./MessageFragment.gql" 2 | 3 | subscription messageAdded { 4 | messageAdded { 5 | ...Message 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /.test-todo/test-ssr-composition/src/graphql/MessageFragment.gql: -------------------------------------------------------------------------------- 1 | fragment Message on Message { 2 | id 3 | text 4 | } 5 | -------------------------------------------------------------------------------- /.test-todo/test-ssr-composition/src/graphql/Messages.gql: -------------------------------------------------------------------------------- 1 | #import "./MessageFragment.gql" 2 | 3 | query messages { 4 | messages { 5 | ...Message 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /.test-todo/test-ssr-composition/src/graphql/UploadFile.gql: -------------------------------------------------------------------------------- 1 | #import "./FileFragment.gql" 2 | 3 | mutation uploadFile ($file: Upload!) { 4 | singleUpload (file: $file) { 5 | ...file 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /.test-todo/test-ssr-composition/src/main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import VueCompositionAPI, { provide } from '@vue/composition-api' 3 | import { DefaultApolloClient } from '@vue/apollo-composable' 4 | import App from './App.vue' 5 | import { createRouter } from './router' 6 | import { createClient } from './vue-apollo' 7 | 8 | Vue.use(VueCompositionAPI) 9 | 10 | Vue.config.productionTip = false 11 | 12 | export async function createApp ({ 13 | beforeApp = () => {}, 14 | afterApp = () => {}, 15 | } = {}) { 16 | const router = createRouter() 17 | 18 | const apolloClient = createClient({ 19 | ssr: process.server, 20 | }) 21 | 22 | await beforeApp({ 23 | router, 24 | apolloClient, 25 | }) 26 | 27 | const app = new Vue({ 28 | router, 29 | 30 | setup () { 31 | provide(DefaultApolloClient, apolloClient) 32 | }, 33 | 34 | render: h => h(App), 35 | }) 36 | 37 | const result = { 38 | app, 39 | router, 40 | apolloClient, 41 | } 42 | 43 | await afterApp(result) 44 | 45 | return result 46 | } 47 | -------------------------------------------------------------------------------- /.test-todo/test-ssr-composition/src/router/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import VueRouter from 'vue-router' 3 | import Home from '../views/Home.vue' 4 | 5 | Vue.use(VueRouter) 6 | 7 | export function createRouter () { 8 | const routes = [ 9 | { 10 | path: '/', 11 | name: 'home', 12 | component: Home, 13 | }, 14 | { 15 | path: '/apollo', 16 | name: 'apollo', 17 | component: () => import(/* webpackChunkName: "apollo" */ '../components/ApolloExample.vue'), 18 | }, 19 | { 20 | path: '/apollo-loading', 21 | name: 'apollo-loading', 22 | component: () => import(/* webpackChunkName: "apollo-loading" */ '../components/ApolloLoading.vue'), 23 | }, 24 | { 25 | path: '/hello', 26 | name: 'hello', 27 | component: () => import(/* webpackChunkName: "hello" */ '../components/HelloWorld.vue'), 28 | }, 29 | { 30 | path: '/about', 31 | name: 'about', 32 | // route level code-splitting 33 | // this generates a separate chunk (about.[hash].js) for this route 34 | // which is lazy-loaded when the route is visited. 35 | component: () => import(/* webpackChunkName: "about" */ '../views/About.vue'), 36 | }, 37 | ] 38 | 39 | const router = new VueRouter({ 40 | mode: 'history', 41 | base: process.env.BASE_URL, 42 | routes, 43 | }) 44 | 45 | return router 46 | } 47 | -------------------------------------------------------------------------------- /.test-todo/test-ssr-composition/src/views/About.vue: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /.test-todo/test-ssr-composition/src/views/Home.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 42 | -------------------------------------------------------------------------------- /.test-todo/test-ssr-composition/tests/e2e/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: [ 3 | 'cypress', 4 | ], 5 | env: { 6 | mocha: true, 7 | 'cypress/globals': true, 8 | }, 9 | rules: { 10 | strict: 'off', 11 | }, 12 | } 13 | -------------------------------------------------------------------------------- /.test-todo/test-ssr-composition/tests/e2e/plugins/index.js: -------------------------------------------------------------------------------- 1 | // https://docs.cypress.io/guides/guides/plugins-guide.html 2 | 3 | // if you need a custom webpack configuration you can uncomment the following import 4 | // and then use the `file:preprocessor` event 5 | // as explained in the cypress docs 6 | // https://docs.cypress.io/api/plugins/preprocessors-api.html#Examples 7 | 8 | /* eslint-disable import/no-extraneous-dependencies, global-require, arrow-body-style */ 9 | // const webpack = require('@cypress/webpack-preprocessor') 10 | 11 | module.exports = (on, config) => { 12 | // on('file:preprocessor', webpack({ 13 | // webpackOptions: require('@vue/cli-service/webpack.config'), 14 | // watchOptions: {} 15 | // })) 16 | 17 | return Object.assign({}, config, { 18 | fixturesFolder: 'tests/e2e/fixtures', 19 | integrationFolder: 'tests/e2e/specs', 20 | screenshotsFolder: 'tests/e2e/screenshots', 21 | videosFolder: 'tests/e2e/videos', 22 | supportFile: 'tests/e2e/support/index.js', 23 | }) 24 | } 25 | -------------------------------------------------------------------------------- /.test-todo/test-ssr-composition/tests/e2e/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 is will overwrite an existing command -- 25 | // Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... }) 26 | -------------------------------------------------------------------------------- /.test-todo/test-ssr-composition/tests/e2e/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 | -------------------------------------------------------------------------------- /.test-todo/test-ssr-composition/vue.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('@vue/cli-service').ProjectOptions} */ 2 | module.exports = { 3 | pluginOptions: { 4 | apollo: { 5 | enableMocks: false, 6 | enableEngine: false, 7 | }, 8 | }, 9 | 10 | chainWebpack (config) { 11 | config.resolve.symlinks(false) 12 | config.externals([ 13 | 'utf-8-validate', 14 | 'bufferutil', 15 | ]) 16 | config.module.noParse([ 17 | /iconv-loader/, 18 | ]) 19 | config.resolve.alias.set('vue-demi', '@vue/composition-api') 20 | }, 21 | } 22 | -------------------------------------------------------------------------------- /.test-todo/test-ssr/.browserslistrc: -------------------------------------------------------------------------------- 1 | > 1% 2 | last 2 versions 3 | -------------------------------------------------------------------------------- /.test-todo/test-ssr/.editorconfig: -------------------------------------------------------------------------------- 1 | [*.{js,jsx,ts,tsx,vue}] 2 | indent_style = space 3 | indent_size = 2 4 | trim_trailing_whitespace = true 5 | insert_final_newline = true 6 | -------------------------------------------------------------------------------- /.test-todo/test-ssr/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | 5 | /tests/e2e/videos/ 6 | /tests/e2e/screenshots/ 7 | 8 | # local env files 9 | .env.local 10 | .env.*.local 11 | 12 | # Log files 13 | npm-debug.log* 14 | yarn-debug.log* 15 | yarn-error.log* 16 | 17 | # Editor directories and files 18 | .idea 19 | .vscode 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | 26 | /live/ 27 | -------------------------------------------------------------------------------- /.test-todo/test-ssr/README.md: -------------------------------------------------------------------------------- 1 | # ssr 2 | 3 | ## Project setup 4 | ``` 5 | yarn install 6 | ``` 7 | 8 | ### Compiles and hot-reloads for development 9 | ``` 10 | yarn serve 11 | ``` 12 | 13 | ### Compiles and minifies for production 14 | ``` 15 | yarn build 16 | ``` 17 | 18 | ### Run your end-to-end tests 19 | ``` 20 | yarn test:e2e 21 | ``` 22 | 23 | ### Customize configuration 24 | See [Configuration Reference](https://cli.vuejs.org/config/). 25 | -------------------------------------------------------------------------------- /.test-todo/test-ssr/apollo-server/context.js: -------------------------------------------------------------------------------- 1 | import { db } from './utils/db' 2 | import { processUpload } from './utils/upload' 3 | 4 | // Context passed to all resolvers (third argument) 5 | // req => Query 6 | // connection => Subscription 7 | // eslint-disable-next-line no-unused-vars 8 | export default ({ req, connection }) => { 9 | return { 10 | db, 11 | processUpload, 12 | 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /.test-todo/test-ssr/apollo-server/data-sources.js: -------------------------------------------------------------------------------- 1 | export default function () { 2 | return {} 3 | } 4 | -------------------------------------------------------------------------------- /.test-todo/test-ssr/apollo-server/directives.js: -------------------------------------------------------------------------------- 1 | export default { 2 | // Schema directives 3 | // https://www.apollographql.com/docs/graphql-tools/schema-directives.html 4 | } 5 | -------------------------------------------------------------------------------- /.test-todo/test-ssr/apollo-server/mocks.js: -------------------------------------------------------------------------------- 1 | // Enable mocking in vue.config.js with `"pluginOptions": { "enableMocks": true }` 2 | // Customize mocking: https://www.apollographql.com/docs/graphql-tools/mocking.html#Customizing-mocks 3 | export default { 4 | // Mock resolvers here 5 | } 6 | -------------------------------------------------------------------------------- /.test-todo/test-ssr/apollo-server/schema.graphql: -------------------------------------------------------------------------------- 1 | "Included scalars" 2 | scalar JSON 3 | scalar Upload 4 | 5 | "It will increment!" 6 | type Counter { 7 | "Number of increments" 8 | count: Int! 9 | "Full message for testing" 10 | countStr: String 11 | } 12 | 13 | "A text message send by users" 14 | type Message { 15 | id: ID! 16 | "Message content" 17 | text: String! 18 | } 19 | 20 | "Input from user to create a message" 21 | input MessageInput { 22 | "Message content" 23 | text: String! 24 | } 25 | 26 | type File { 27 | id: ID! 28 | path: String! 29 | filename: String! 30 | mimetype: String! 31 | encoding: String! 32 | } 33 | 34 | 35 | type Query { 36 | "Test query with a parameter" 37 | hello(name: String): String! 38 | "List of messages sent by users" 39 | messages: [Message] 40 | uploads: [File] 41 | 42 | } 43 | 44 | type Mutation { 45 | myMutation: String! 46 | "Add a message and publish it on 'messages' subscription channel" 47 | addMessage (input: MessageInput!): Message! 48 | singleUpload (file: Upload!): File! 49 | multipleUpload (files: [Upload!]!): [File!]! 50 | 51 | } 52 | 53 | type Subscription { 54 | mySub: String! 55 | "This will update every 2 seconds" 56 | counter: Counter! 57 | "When a new message is added" 58 | messageAdded: Message! 59 | 60 | } 61 | -------------------------------------------------------------------------------- /.test-todo/test-ssr/apollo-server/server.js: -------------------------------------------------------------------------------- 1 | import ssrMiddleware from '@akryum/vue-cli-plugin-ssr/lib/app' 2 | import path from 'path' 3 | import express from 'express' 4 | 5 | export default app => { 6 | app.use('/files', express.static(path.resolve(__dirname, '../live/uploads'))) 7 | 8 | ssrMiddleware(app, { prodOnly: true }) 9 | } 10 | -------------------------------------------------------------------------------- /.test-todo/test-ssr/apollo-server/type-defs.js: -------------------------------------------------------------------------------- 1 | import fs from 'fs' 2 | import path from 'path' 3 | 4 | export default fs.readFileSync(path.resolve(__dirname, './schema.graphql'), { encoding: 'utf8' }) 5 | -------------------------------------------------------------------------------- /.test-todo/test-ssr/apollo-server/utils/db.js: -------------------------------------------------------------------------------- 1 | import Lowdb from 'lowdb' 2 | // import FileSync from 'lowdb/adapters/FileSync' 3 | import Memory from 'lowdb/adapters/Memory' 4 | import mkdirp from 'mkdirp' 5 | import { resolve } from 'path' 6 | 7 | mkdirp(resolve(__dirname, '../../live')) 8 | 9 | // export const db = new Lowdb(new FileSync(resolve(__dirname, '../../live/db.json'))) 10 | export const db = new Lowdb(new Memory()) 11 | 12 | // Seed an empty DB 13 | db.defaults({ 14 | messages: [ 15 | { 16 | id: 'a', 17 | text: 'Message 1', 18 | }, 19 | { 20 | id: 'b', 21 | text: 'Message 2', 22 | }, 23 | { 24 | id: 'c', 25 | text: 'Message 3', 26 | }, 27 | ], 28 | uploads: [], 29 | }).write() 30 | -------------------------------------------------------------------------------- /.test-todo/test-ssr/apollo-server/utils/upload.js: -------------------------------------------------------------------------------- 1 | import { createWriteStream } from 'fs' 2 | import { resolve } from 'path' 3 | import { sync } from 'mkdirp' 4 | import { generate } from 'shortid' 5 | import { db } from './db' 6 | 7 | const uploadDir = resolve(__dirname, '../../live/uploads') 8 | 9 | // Ensure upload directory exists 10 | sync(uploadDir) 11 | 12 | const storeUpload = async ({ stream, filename }) => { 13 | const id = generate() 14 | const file = `${id}-${filename}` 15 | const path = `${uploadDir}/${file}` 16 | const urlPath = `files/${file}` 17 | 18 | return new Promise((resolve, reject) => 19 | stream 20 | .pipe(createWriteStream(path)) 21 | .on('finish', () => resolve({ id, path: urlPath })) 22 | .on('error', reject), 23 | ) 24 | } 25 | 26 | const recordFile = file => 27 | db 28 | .get('uploads') 29 | .push(file) 30 | .last() 31 | .write() 32 | 33 | export async function processUpload (file) { 34 | const { stream, filename, mimetype, encoding } = await file 35 | const { id, path } = await storeUpload({ stream, filename }) 36 | return recordFile({ id, filename, mimetype, encoding, path }) 37 | } 38 | -------------------------------------------------------------------------------- /.test-todo/test-ssr/apollo.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | 3 | // Load .env files 4 | const { loadEnv } = require('vue-cli-plugin-apollo/utils/load-env') 5 | const env = loadEnv([ 6 | path.resolve(__dirname, '.env'), 7 | path.resolve(__dirname, '.env.local'), 8 | ]) 9 | 10 | module.exports = { 11 | client: { 12 | service: env.VUE_APP_APOLLO_ENGINE_SERVICE, 13 | includes: ['src/**/*.{js,jsx,ts,tsx,vue,gql}'], 14 | }, 15 | service: { 16 | name: env.VUE_APP_APOLLO_ENGINE_SERVICE, 17 | localSchemaFile: path.resolve(__dirname, './node_modules/.temp/graphql/schema.json'), 18 | }, 19 | engine: { 20 | endpoint: process.env.APOLLO_ENGINE_API_ENDPOINT, 21 | apiKey: env.VUE_APP_APOLLO_ENGINE_KEY, 22 | }, 23 | } 24 | -------------------------------------------------------------------------------- /.test-todo/test-ssr/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | '@vue/cli-plugin-babel/preset', 4 | ], 5 | } 6 | -------------------------------------------------------------------------------- /.test-todo/test-ssr/cypress.json: -------------------------------------------------------------------------------- 1 | { 2 | "pluginsFile": "tests/e2e/plugins/index.js" 3 | } 4 | -------------------------------------------------------------------------------- /.test-todo/test-ssr/postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | autoprefixer: {}, 4 | }, 5 | } 6 | -------------------------------------------------------------------------------- /.test-todo/test-ssr/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuejs/apollo/fb027e6adf4d4129fb26f8c918060771a0afd59b/.test-todo/test-ssr/public/favicon.ico -------------------------------------------------------------------------------- /.test-todo/test-ssr/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | ssr 9 | 10 | 11 | 14 |
15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /.test-todo/test-ssr/public/index.ssr.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | {{ title }} 9 | {{{ renderResourceHints() }}} 10 | {{{ renderStyles() }}} 11 | 12 | 13 | 14 | {{{ renderState() }}} 15 | {{{ renderState({ contextKey: 'apolloState', windowKey: '__APOLLO_STATE__' }) }}} 16 | {{{ renderScripts() }}} 17 | 18 | 19 | -------------------------------------------------------------------------------- /.test-todo/test-ssr/src/App.vue: -------------------------------------------------------------------------------- 1 | 24 | 25 | 38 | 39 | 70 | -------------------------------------------------------------------------------- /.test-todo/test-ssr/src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuejs/apollo/fb027e6adf4d4129fb26f8c918060771a0afd59b/.test-todo/test-ssr/src/assets/logo.png -------------------------------------------------------------------------------- /.test-todo/test-ssr/src/components/ApolloLoading.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 22 | -------------------------------------------------------------------------------- /.test-todo/test-ssr/src/components/HelloWorld.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 35 | -------------------------------------------------------------------------------- /.test-todo/test-ssr/src/entry-client.js: -------------------------------------------------------------------------------- 1 | import 'isomorphic-fetch' 2 | import { loadAsyncComponents } from '@akryum/vue-cli-plugin-ssr/client' 3 | 4 | import { createApp } from './main' 5 | 6 | createApp({ 7 | async beforeApp ({ 8 | router, 9 | }) { 10 | await loadAsyncComponents({ router }) 11 | }, 12 | 13 | afterApp ({ 14 | app, 15 | router, 16 | }) { 17 | router.onReady(() => { 18 | app.$mount('#app') 19 | }) 20 | }, 21 | }) 22 | -------------------------------------------------------------------------------- /.test-todo/test-ssr/src/entry-server.js: -------------------------------------------------------------------------------- 1 | import 'isomorphic-fetch' 2 | import * as ApolloSSR from '@vue/apollo-ssr' 3 | import { createApp } from './main' 4 | 5 | const prepareUrlForRouting = url => { 6 | const { BASE_URL } = process.env 7 | return url.startsWith(BASE_URL.replace(/\/$/, '')) 8 | ? url.slice(BASE_URL.length) 9 | : url 10 | } 11 | 12 | export default context => { 13 | return new Promise(async (resolve, reject) => { 14 | const { 15 | app, 16 | router, 17 | apolloProvider, 18 | } = await createApp() 19 | 20 | router.push(prepareUrlForRouting(context.url)) 21 | 22 | router.onReady(() => { 23 | context.rendered = () => { 24 | // Same for Apollo client cache 25 | context.apolloState = ApolloSSR.getStates(apolloProvider.clients) 26 | } 27 | resolve(app) 28 | }, reject) 29 | }) 30 | } 31 | -------------------------------------------------------------------------------- /.test-todo/test-ssr/src/graphql/AddMessage.gql: -------------------------------------------------------------------------------- 1 | #import "./MessageFragment.gql" 2 | 3 | mutation addMessage ($input: MessageInput!) { 4 | addMessage (input: $input) { 5 | ...Message 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /.test-todo/test-ssr/src/graphql/FileFragment.gql: -------------------------------------------------------------------------------- 1 | fragment file on File { 2 | id 3 | path 4 | filename 5 | mimetype 6 | encoding 7 | } 8 | -------------------------------------------------------------------------------- /.test-todo/test-ssr/src/graphql/Files.gql: -------------------------------------------------------------------------------- 1 | #import "./FileFragment.gql" 2 | 3 | query files { 4 | files: uploads { 5 | ...file 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /.test-todo/test-ssr/src/graphql/HelloWorld.gql: -------------------------------------------------------------------------------- 1 | query HelloWorld ($name: String) { 2 | hello (name: $name) 3 | } 4 | -------------------------------------------------------------------------------- /.test-todo/test-ssr/src/graphql/MessageAdded.gql: -------------------------------------------------------------------------------- 1 | #import "./MessageFragment.gql" 2 | 3 | subscription messageAdded { 4 | messageAdded { 5 | ...Message 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /.test-todo/test-ssr/src/graphql/MessageFragment.gql: -------------------------------------------------------------------------------- 1 | fragment Message on Message { 2 | id 3 | text 4 | } 5 | -------------------------------------------------------------------------------- /.test-todo/test-ssr/src/graphql/Messages.gql: -------------------------------------------------------------------------------- 1 | #import "./MessageFragment.gql" 2 | 3 | query messages { 4 | messages { 5 | ...Message 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /.test-todo/test-ssr/src/graphql/UploadFile.gql: -------------------------------------------------------------------------------- 1 | #import "./FileFragment.gql" 2 | 3 | mutation uploadFile ($file: Upload!) { 4 | singleUpload (file: $file) { 5 | ...file 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /.test-todo/test-ssr/src/main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import App from './App.vue' 3 | import { createRouter } from './router' 4 | import { createProvider } from './vue-apollo' 5 | 6 | Vue.config.productionTip = false 7 | 8 | export async function createApp ({ 9 | beforeApp = () => {}, 10 | afterApp = () => {}, 11 | } = {}) { 12 | const router = createRouter() 13 | 14 | const apolloProvider = createProvider({ 15 | ssr: process.server, 16 | }) 17 | 18 | await beforeApp({ 19 | router, 20 | 21 | apolloProvider, 22 | }) 23 | 24 | const app = new Vue({ 25 | router, 26 | apolloProvider, 27 | render: h => h(App), 28 | }) 29 | 30 | const result = { 31 | app, 32 | router, 33 | 34 | apolloProvider, 35 | } 36 | 37 | await afterApp(result) 38 | 39 | return result 40 | } 41 | -------------------------------------------------------------------------------- /.test-todo/test-ssr/src/router/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import VueRouter from 'vue-router' 3 | import Home from '../views/Home.vue' 4 | 5 | Vue.use(VueRouter) 6 | 7 | export function createRouter () { 8 | const routes = [ 9 | { 10 | path: '/', 11 | name: 'home', 12 | component: Home, 13 | }, 14 | { 15 | path: '/apollo', 16 | name: 'apollo', 17 | component: () => import(/* webpackChunkName: "apollo" */ '../components/ApolloExample.vue'), 18 | }, 19 | { 20 | path: '/apollo-loading', 21 | name: 'apollo-loading', 22 | component: () => import(/* webpackChunkName: "apollo-loading" */ '../components/ApolloLoading.vue'), 23 | }, 24 | { 25 | path: '/hello', 26 | name: 'hello', 27 | component: () => import(/* webpackChunkName: "hello" */ '../components/HelloWorld.vue'), 28 | }, 29 | { 30 | path: '/about', 31 | name: 'about', 32 | // route level code-splitting 33 | // this generates a separate chunk (about.[hash].js) for this route 34 | // which is lazy-loaded when the route is visited. 35 | component: () => import(/* webpackChunkName: "about" */ '../views/About.vue'), 36 | }, 37 | ] 38 | 39 | const router = new VueRouter({ 40 | mode: 'history', 41 | base: process.env.BASE_URL, 42 | routes, 43 | }) 44 | 45 | return router 46 | } 47 | -------------------------------------------------------------------------------- /.test-todo/test-ssr/src/views/About.vue: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /.test-todo/test-ssr/src/views/Home.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 15 | -------------------------------------------------------------------------------- /.test-todo/test-ssr/tests/e2e/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: [ 3 | 'cypress', 4 | ], 5 | env: { 6 | mocha: true, 7 | 'cypress/globals': true, 8 | }, 9 | rules: { 10 | strict: 'off', 11 | }, 12 | } 13 | -------------------------------------------------------------------------------- /.test-todo/test-ssr/tests/e2e/plugins/index.js: -------------------------------------------------------------------------------- 1 | // https://docs.cypress.io/guides/guides/plugins-guide.html 2 | 3 | // if you need a custom webpack configuration you can uncomment the following import 4 | // and then use the `file:preprocessor` event 5 | // as explained in the cypress docs 6 | // https://docs.cypress.io/api/plugins/preprocessors-api.html#Examples 7 | 8 | /* eslint-disable import/no-extraneous-dependencies, global-require, arrow-body-style */ 9 | // const webpack = require('@cypress/webpack-preprocessor') 10 | 11 | module.exports = (on, config) => { 12 | // on('file:preprocessor', webpack({ 13 | // webpackOptions: require('@vue/cli-service/webpack.config'), 14 | // watchOptions: {} 15 | // })) 16 | 17 | return Object.assign({}, config, { 18 | fixturesFolder: 'tests/e2e/fixtures', 19 | integrationFolder: 'tests/e2e/specs', 20 | screenshotsFolder: 'tests/e2e/screenshots', 21 | videosFolder: 'tests/e2e/videos', 22 | supportFile: 'tests/e2e/support/index.js', 23 | }) 24 | } 25 | -------------------------------------------------------------------------------- /.test-todo/test-ssr/tests/e2e/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 is will overwrite an existing command -- 25 | // Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... }) 26 | -------------------------------------------------------------------------------- /.test-todo/test-ssr/tests/e2e/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 | -------------------------------------------------------------------------------- /.test-todo/test-ssr/vue.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('@vue/cli-service').ProjectOptions} */ 2 | module.exports = { 3 | pluginOptions: { 4 | apollo: { 5 | enableMocks: false, 6 | enableEngine: false, 7 | }, 8 | }, 9 | 10 | chainWebpack (config) { 11 | config.resolve.symlinks(false) 12 | config.externals([ 13 | 'utf-8-validate', 14 | 'bufferutil', 15 | ]) 16 | config.module.noParse([ 17 | /iconv-loader/, 18 | ]) 19 | }, 20 | } 21 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "eslint.validate": [ 3 | "javascript", 4 | "javascriptreact", 5 | "vue" 6 | ], 7 | "eslint.enable": true, 8 | "typescript.tsdk": "node_modules/typescript/lib" 9 | } 10 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | ## Development setup 4 | 5 | Install dependencies: 6 | 7 | ``` 8 | pnpm install 9 | ``` 10 | 11 | Go to a package in `packages`. 12 | 13 | Build the library: 14 | 15 | ``` 16 | pnpm run build 17 | ``` 18 | 19 | Run tests: 20 | 21 | ``` 22 | pnpm run test 23 | ``` 24 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2018-present, Guillaume Chau 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 13 | all 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 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /eslint.config.mjs: -------------------------------------------------------------------------------- 1 | // eslint.config.mjs 2 | import antfu from '@antfu/eslint-config' 3 | 4 | export default antfu({ 5 | ignores: [ 6 | 'node_modules/', 7 | 'dist/', 8 | 'generated/', 9 | '!.*', 10 | 'schema.graphql', 11 | '.test-todo/', 12 | '**/types/test/', 13 | ], 14 | 15 | rules: { 16 | 'ts/no-use-before-define': 'warn', 17 | 'unused-imports/no-unused-vars': 'warn', 18 | 'accessor-pairs': 'off', 19 | }, 20 | }, { 21 | files: [ 22 | 'packages/docs/**', 23 | ], 24 | rules: { 25 | 'no-dupe-keys': 'off', 26 | 'no-new': 'off', 27 | 'no-console': 'off', 28 | }, 29 | }, { 30 | files: [ 31 | 'packages/test-*/**', 32 | '**/*.test.*', 33 | ], 34 | rules: { 35 | 'antfu/no-top-level-await': 'off', 36 | 'no-console': 'off', 37 | 'unused-imports/no-unused-vars': 'off', 38 | 'node/prefer-global/process': 'off', 39 | 'import/no-mutable-exports': 'off', 40 | }, 41 | 42 | languageOptions: { 43 | globals: { 44 | cy: false, 45 | expect: false, 46 | describe: false, 47 | it: false, 48 | before: false, 49 | }, 50 | }, 51 | }, { 52 | files: [ 53 | '**/tests/types/**', 54 | ], 55 | rules: { 56 | 'ts/no-unused-expressions': 'off', 57 | }, 58 | }) 59 | -------------------------------------------------------------------------------- /packages/docs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "private-vue-apollo-docs", 3 | "type": "module", 4 | "version": "4.0.0-alpha.16", 5 | "private": true, 6 | "scripts": { 7 | "dev": "vitepress dev src", 8 | "build": "vitepress build src" 9 | }, 10 | "dependencies": { 11 | "vue-github-button": "^3.0.3" 12 | }, 13 | "devDependencies": { 14 | "vitepress": "^1.0.0-rc.36" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /packages/docs/src/.vitepress/theme/components/SponsorButton.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 23 | 24 | 30 | -------------------------------------------------------------------------------- /packages/docs/src/.vitepress/theme/index.js: -------------------------------------------------------------------------------- 1 | import DefaultTheme from 'vitepress/theme' 2 | import SponsorButton from './components/SponsorButton.vue' 3 | 4 | import './styles/index.pcss' 5 | 6 | export default { 7 | ...DefaultTheme, 8 | enhanceApp({ app }) { 9 | app.component('SponsorButton', SponsorButton) 10 | }, 11 | } 12 | -------------------------------------------------------------------------------- /packages/docs/src/.vitepress/theme/styles/index.pcss: -------------------------------------------------------------------------------- 1 | :root { 2 | --vp-c-brand-1: #5591d8; 3 | --vp-c-brand-2: #336cb0; 4 | --vp-c-brand-3: #1f4c80; 5 | --vp-c-brand-soft: rgba(42, 95, 156, 0.14); 6 | } 7 | -------------------------------------------------------------------------------- /packages/docs/src/api/apollo-provider.md: -------------------------------------------------------------------------------- 1 | # createApolloProvider 2 | 3 | ## Example 4 | 5 | ```js 6 | import { createApolloProvider } from '@vue/apollo-option' 7 | 8 | const apolloProvider = createApolloProvider({ 9 | // Multiple clients support 10 | // Use the 'client' option inside queries 11 | // or '$client' on the apollo definition 12 | clients: { 13 | a: apolloClientA, 14 | b: apolloClientB, 15 | }, 16 | // Default client 17 | defaultClient: apolloClient, 18 | // Default 'apollo' definition 19 | defaultOptions: { 20 | // See 'apollo' definition 21 | // For example: default query options 22 | $query: { 23 | loadingKey: 'loading', 24 | fetchPolicy: 'cache-and-network', 25 | }, 26 | }, 27 | // Watch loading state for all queries 28 | // See 'Smart Query > options > watchLoading' for detail 29 | watchLoading(isLoading, countModifier) { 30 | loading += countModifier 31 | console.log('Global loading', loading, countModifier) 32 | }, 33 | // Global error handler for all smart queries and subscriptions 34 | errorHandler(error) { 35 | console.log('Global error handler') 36 | console.error(error) 37 | }, 38 | // Globally turn off prefetch ssr 39 | prefetch: Boolean, 40 | }) 41 | ``` 42 | 43 | Use the apollo provider into your Vue app: 44 | 45 | ```js 46 | const app = createApp({ /* ... */ }) 47 | app.use(apolloProvider) 48 | ``` 49 | -------------------------------------------------------------------------------- /packages/docs/src/api/dollar-apollo.md: -------------------------------------------------------------------------------- 1 | # Dollar Apollo 2 | 3 | This is the Apollo manager added to any component that uses Apollo. It can be accessed inside a component with `this.$apollo`. 4 | 5 | ## Properties 6 | 7 | - `vm`: related component 8 | - `queries`: object map of the component's Reactive Queries. 9 | - `subscriptions`: object map of the component's Reactive Subscriptions. 10 | - `provider`: injected [Apollo Provider](./apollo-provider.md). 11 | - `loading`: whether at least one query is loading. 12 | - `skipAllQueries`: (setter) boolean to pause or unpause all Reactive Queries. 13 | - `skipAllSubscriptions`: (setter) boolean to pause or unpause all Reactive Subscriptions. 14 | - `skipAll`: (setter) boolean to pause or unpause all Reactive Queries and Reactive Subscriptions. 15 | 16 | ## Methods 17 | 18 | - `query`: execute a query (see [Queries](../guide-option/queries.md)). 19 | - `mutate`: execute a mutation (see [Mutations](../guide-option/mutations.md)). 20 | - `subscribe`: standard Apollo subscribe method (see [Subscriptions](../guide-option/subscriptions.md)). 21 | - `addSmartQuery`: manually add a Reactive Query (not recommended). 22 | - `addSmartSubscription`: add a Reactive Subscription (see [Subscriptions](../guide-option/subscriptions.md)). 23 | - `getClient`: returns the underlying ApolloClient. 24 | -------------------------------------------------------------------------------- /packages/docs/src/api/index.md: -------------------------------------------------------------------------------- 1 | # API Reference 2 | 3 | Welcome to the API Reference! 4 | -------------------------------------------------------------------------------- /packages/docs/src/api/ssr.md: -------------------------------------------------------------------------------- 1 | # ApolloSSR 2 | 3 | ## Usage 4 | 5 | See [SSR guide](../guide-advanced/ssr.md). 6 | 7 | ## Methods 8 | 9 | ### getStates 10 | 11 | Returns the apollo stores states as JavaScript objects. 12 | 13 | ```js 14 | const states = ApolloSSR.getStates(clientsObject, options) 15 | ``` 16 | 17 | `options` defaults to: 18 | 19 | ```js 20 | const defaultOptions = { 21 | // Prefix for the keys of each apollo client state 22 | exportNamespace: '', 23 | } 24 | ``` 25 | 26 | ### exportStates 27 | 28 | Returns the apollo stores states as JavaScript code inside a String. This code can be directly injected to the page HTML inside a ` 34 | ``` 35 | -------------------------------------------------------------------------------- /packages/docs/src/api/use-lazy-query.md: -------------------------------------------------------------------------------- 1 | # useLazyQuery 2 | 3 | Extends [useQuery](./use-query.md) 4 | 5 | ## Additional Return 6 | 7 | - `load(document?, variables?, options?)`: function to start querying. Returns `Promise` if it is the first time the query is called, `false` otherwise. 8 | 9 | Example: 10 | 11 | ```js 12 | const { load, refetch } = useLazyQuery(query, variables, options) 13 | 14 | function fetchOrRefetch() { 15 | load() || refetch() 16 | } 17 | 18 | async function waitForLoad() { 19 | try { 20 | const result = await load() 21 | // do something with result 22 | } 23 | catch (error) { 24 | // handle error 25 | } 26 | } 27 | ``` 28 | -------------------------------------------------------------------------------- /packages/docs/src/guide-advanced/index.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | This guide is a collection of advanced topic articles. 4 | -------------------------------------------------------------------------------- /packages/docs/src/guide-components/index.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | ## What are Apollo components? 4 | 5 | Those are components just like any others. They take a GraphQL document in their prop and use the [scoped slot feature](https://vuejs.org/v2/guide-components-slots.html#Scoped-Slots) to pass down the results. 6 | 7 | The benefit is that you can use those components in the template directly instead of using the `apollo` option of your component. In some cases you don't even need to add a script part at all in your `.vue`! This is all even more declarative. 8 | 9 | Here is a quick example of an [ApolloQuery](./query.md) in a template: 10 | 11 | ```vue 12 | 27 | 28 | 29 | ``` 30 | -------------------------------------------------------------------------------- /packages/docs/src/guide-composable/cache-interaction.md: -------------------------------------------------------------------------------- 1 | # Interacting with cached data 2 | 3 | This section is not available yet. 4 | 5 | In the meantime, see [react apollo docs](https://www.apollographql.com/docs/react/caching/cache-interaction/). 6 | -------------------------------------------------------------------------------- /packages/docs/src/guide-composable/index.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | The Composition API is an API where you write data and logic in an easily composable way inside the `setup` option. 4 | 5 | If you are using Typescript, it is strongly recommended to start using the Composition API as its typing capabilities are unmatched by any other Vue API. 6 | 7 | Learn more about the Composition API [here](https://vue-composition-api-rfc.netlify.com/). 8 | 9 | Here is an example using this API: 10 | 11 | ```vue 12 | 26 | ``` 27 | -------------------------------------------------------------------------------- /packages/docs/src/guide-option/index.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | The Option API is based on the `apollo` Vue component option. 4 | 5 | For example: 6 | 7 | ```vue 8 | 15 | ``` 16 | -------------------------------------------------------------------------------- /packages/docs/src/guide-option/setup.md: -------------------------------------------------------------------------------- 1 | # Setup 2 | 3 | Make sure you have [installed Apollo Client](../guide/installation.md). 4 | 5 | ## 1. Install @vue/apollo-option 6 | 7 | ``` 8 | npm install --save @vue/apollo-option 9 | ``` 10 | 11 | Or: 12 | 13 | ``` 14 | yarn add @vue/apollo-option 15 | ``` 16 | 17 | ## 2. Create the Apollo client 18 | 19 | ```js 20 | import { ApolloClient, InMemoryCache } from '@apollo/client/core' 21 | 22 | const cache = new InMemoryCache() 23 | 24 | const apolloClient = new ApolloClient({ 25 | cache, 26 | uri: 'http://localhost:4042/graphql', 27 | }) 28 | ``` 29 | 30 | ::: warning 31 | Use the `@apollo/client/core` import path otherwise you will also import React. 32 | ::: 33 | 34 | ## 3. Create the Apollo provider 35 | 36 | The provider holds the Apollo client instances that can then be used by all the child components. 37 | 38 | ```js 39 | import { createApolloProvider } from '@vue/apollo-option' 40 | 41 | const apolloProvider = createApolloProvider({ 42 | defaultClient: apolloClient, 43 | }) 44 | ``` 45 | 46 | ## 4. Add the provider to your app 47 | 48 | Add it to your app with the `app.use` function: 49 | 50 | ```js 51 | import { createApp, h } from 'vue' 52 | 53 | const app = createApp({ 54 | render: () => h(App), 55 | }) 56 | 57 | app.use(apolloProvider) 58 | ``` 59 | 60 | You are now ready to use Apollo in your components! 61 | -------------------------------------------------------------------------------- /packages/docs/src/guide-option/usage.md: -------------------------------------------------------------------------------- 1 | # Usage in Vue components 2 | 3 | After installing `vue-apollo` in your app, all your components can now use Apollo through the `apollo` special option. 4 | 5 | ## `apollo` options 6 | 7 | To declare apollo queries in your Vue component, add the `apollo` object in the component options: 8 | 9 | ```js 10 | new Vue({ 11 | apollo: { 12 | // Apollo specific options 13 | }, 14 | }) 15 | ``` 16 | 17 | In a `.vue` file: 18 | 19 | ```vue 20 | 23 | 24 | 31 | ``` 32 | 33 | ### Special options 34 | 35 | In the `apollo` option, there are special options that begin with `$` in the `apollo` object. 36 | 37 | Learn more about those special options in the [Special options section](./special-options.md). 38 | 39 | ## `$apollo` 40 | 41 | All the components under the one which has the `apolloProvider` option have an `$apollo` helper available. This is the glue between your component and Apollo and it does all the heavy lifting for you (including automatic updates and teardowns). 42 | 43 | You can access the [apollo-client](https://www.apollographql.com/docs/react/) instances with `this.$apollo.provider.defaultClient` or `this.$apollo.provider.clients.` (for [Multiple clients](./multiple-clients.md)) in all your vue components. 44 | 45 | If you are curious, see [$apollo API](../api/dollar-apollo.md). 46 | -------------------------------------------------------------------------------- /packages/docs/src/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: home 3 | hero: 4 | name: Vue Apollo 5 | text: GraphQL 6 | tagline: Effortless GraphQL in your Vue app! 7 | image: 8 | src: /hero.svg 9 | alt: Vue Apollo 10 | actions: 11 | - theme: brand 12 | text: Get Started 13 | link: /guide/ 14 | features: 15 | - title: Automatic updates 16 | details: Don't think about updating the UI or refetching the queries! 17 | icon: ✨ 18 | - title: Supports all Vue APIs 19 | details: Option API, Composition API or Components 20 | icon: 🧩 21 | - title: SSR-ready 22 | details: Run your queries on the server before rendering the page HTML 23 | icon: 🌐 24 | --- 25 | 26 | 27 | 28 |

Sponsors

29 | 30 |

31 | 32 | 33 | 34 |

35 | -------------------------------------------------------------------------------- /packages/docs/src/public/error-log.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuejs/apollo/fb027e6adf4d4129fb26f8c918060771a0afd59b/packages/docs/src/public/error-log.jpeg -------------------------------------------------------------------------------- /packages/docs/src/public/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuejs/apollo/fb027e6adf4d4129fb26f8c918060771a0afd59b/packages/docs/src/public/favicon.png -------------------------------------------------------------------------------- /packages/docs/src/public/vue-apollo-graphql.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuejs/apollo/fb027e6adf4d4129fb26f8c918060771a0afd59b/packages/docs/src/public/vue-apollo-graphql.png -------------------------------------------------------------------------------- /packages/docs/src/zh-cn/api/apollo-provider.md: -------------------------------------------------------------------------------- 1 | # ApolloProvider 2 | 3 | ## 构造函数 4 | 5 | ```js 6 | const apolloProvider = createApolloProvider({ 7 | // 支持多客户端 8 | // 在查询中使用 'client' 选项 9 | // 或在 apollo 定义中使用 '$client' 10 | clients: { 11 | a: apolloClientA, 12 | b: apolloClientB, 13 | }, 14 | // 默认客户端 15 | defaultClient: apolloClient, 16 | // 'apollo' 对象的默认定义 17 | defaultOptions: { 18 | // 详见 'apollo' 的定义 19 | // 例如:默认查询选项 20 | $query: { 21 | loadingKey: 'loading', 22 | fetchPolicy: 'cache-and-network', 23 | }, 24 | }, 25 | // 查看所有查询的加载状态 26 | // 详见 '智能查询 > 选项 > watchLoading' 27 | watchLoading(isLoading, countModifier) { 28 | loading += countModifier 29 | console.log('Global loading', loading, countModifier) 30 | }, 31 | // 所有智能查询和订阅的全局错误处理函数 32 | errorHandler(error) { 33 | console.log('Global error handler') 34 | console.error(error) 35 | }, 36 | // 全局关闭 ssr 的预取 37 | prefetch: Boolean, 38 | }) 39 | ``` 40 | 41 | 在你的 Vue 应用程序中使用 apollo provider: 42 | 43 | ```js 44 | new Vue({ 45 | el: '#app', 46 | apolloProvider, 47 | render: h => h(App), 48 | }) 49 | ``` 50 | -------------------------------------------------------------------------------- /packages/docs/src/zh-cn/api/apollo-subscribe-to-more.md: -------------------------------------------------------------------------------- 1 | # ApolloSubscribeToMore 组件 2 | 3 | 示例: 4 | 5 | ```vue 6 | 27 | 28 | 49 | ``` 50 | 51 | ## Props 52 | 53 | - `document`:包含订阅的 GraphQL 文档,或一个接收 `gql` 标签作为参数并返回转换后的文档的函数。 54 | - `variables`:将自动更新订阅变量的对象。 55 | - `updateQuery`:可以根据需要更新查询结果的函数。 56 | -------------------------------------------------------------------------------- /packages/docs/src/zh-cn/api/dollar-apollo.md: -------------------------------------------------------------------------------- 1 | # Dollar Apollo 2 | 3 | 这是添加到任何使用 Apollo 的组件中的 Apollo 管理器。它可以在一个组件内通过 `this.$apollo` 访问到。 4 | 5 | ## 属性 6 | 7 | - `vm`:关联的组件。 8 | - `queries`:组件的智能查询的数组。 9 | - `subscriptions`:组件的智能订阅的数组。 10 | - `provider`:注入的 [Apollo Provider](./apollo-provider.md)。 11 | - `loading`:是否至少有一个查询正在加载。 12 | - `skipAllQueries`:(setter) 布尔值,用于暂停或取消暂停所有智能查询。 13 | - `skipAllSubscriptions`:(setter) 布尔值,用于暂停或取消暂停所有智能订阅。 14 | - `skipAll`:(setter) 布尔值,用于暂停或取消暂停所有智能查询和智能订阅。 15 | 16 | ## 方法 17 | 18 | - `query`:执行一个查询(详见 [查询](../guide-option/queries.md))。 19 | - `mutate`:执行一个变更(详见 [变更](../guide-option/mutations.md))。 20 | - `subscribe`:标准的 Apollo 订阅方法(详见 [订阅](../guide-option/subscriptions.md))。 21 | - `addSmartQuery`:手动添加一个智能查询(不推荐使用)。 22 | - `addSmartSubscription`:添加一个智能订阅(详见 [订阅](../guide-option/subscriptions.md))。 23 | - `getClient`:返回底层的 ApolloClient。 24 | -------------------------------------------------------------------------------- /packages/docs/src/zh-cn/api/index.md: -------------------------------------------------------------------------------- 1 | # API 参考 2 | 3 | 欢迎查看 API 参考! 4 | 5 | ::: warning Work-in-Progress 6 | 如果你发现缺少了某些东西,请创建一个代码合并请求! 7 | ::: 8 | -------------------------------------------------------------------------------- /packages/docs/src/zh-cn/api/smart-subscription.md: -------------------------------------------------------------------------------- 1 | # 智能订阅 2 | 3 | 每个在组件中的 `apollo.$subscribe` 选项中声明的订阅都会创建一个智能订阅对象。 4 | 5 | ## 选项 6 | 7 | - `query`:GraphQL 文档(可以是一个文件或一个 `gql` 字符串)。 8 | - `variables`:对象或返回对象的响应式函数。每个键将用 `'$'` 映射到 GraphQL 文档中,例如 `foo` 将变为 `$foo`。 9 | - `throttle`:变量更新节流时间(毫秒)。 10 | - `debounce`:变量更新防抖时间(毫秒)。 11 | - `result(data, key)` 是收到结果时调用的钩子。 12 | - `error(error)` 是有错误时调用的钩子。`error` 是一个具有 `graphQLErrors` 属性或 `networkError` 属性的 Apollo 错误对象。 13 | - `skip` 是一个布尔值或一个返回布尔值的(响应式)函数。该函数的参数一个是当前组件,另一个是智能查询的键名,因此可以在 `$query` 或是 `ApolloProvider` 的 `defaultOptions` 中使用。 14 | 15 | ## 属性 16 | 17 | ### skip 18 | 19 | 你可以使用 `skip` 来暂停或停止暂停: 20 | 21 | ```js 22 | this.$apollo.subscriptions.users.skip = true 23 | ``` 24 | 25 | ## 方法 26 | 27 | ### refresh 28 | 29 | 停止并重新启动查询: 30 | 31 | ```js 32 | this.$apollo.subscriptions.users.refresh() 33 | ``` 34 | 35 | ### start 36 | 37 | 开始查询: 38 | 39 | ```js 40 | this.$apollo.subscriptions.users.start() 41 | ``` 42 | 43 | ### stop 44 | 45 | 停止查询: 46 | 47 | ```js 48 | this.$apollo.subscriptions.users.stop() 49 | ``` 50 | -------------------------------------------------------------------------------- /packages/docs/src/zh-cn/api/ssr.md: -------------------------------------------------------------------------------- 1 | # ApolloSSR 2 | 3 | ## 用法 4 | 5 | 详见 [SSR 指南](../guide-advanced/ssr.md)。 6 | 7 | ## 方法 8 | 9 | ### getStates 10 | 11 | 将 apollo store 状态作为 JavaScript 对象返回。 12 | 13 | ```js 14 | const states = ApolloSSR.getStates(apolloProvider, options) 15 | ``` 16 | 17 | `options` 的默认值是: 18 | 19 | ```js 20 | const defaultOptions = { 21 | // 每个 apollo 客户端状态的 key 的前缀 22 | exportNamespace: '', 23 | } 24 | ``` 25 | 26 | ### exportStates 27 | 28 | 将 apollo store 状态作为字符串内的 JavaScript 代码返回。该代码可以直接注入到页面 HTML 的 ` 34 | ``` 35 | -------------------------------------------------------------------------------- /packages/docs/src/zh-cn/api/use-subscription.md: -------------------------------------------------------------------------------- 1 | # useSubscription 2 | 3 | ## 参数 4 | 5 | - `document`:包含订阅的 GraphQL 文档。也可以是一个 `Ref` 或是一个返回文档的函数(将会是响应式的)。 6 | 7 | - `variables`:(默认值:`null`)变量对象。也可以是一个 `Ref` 、一个响应式对象或是一个返回变量对象的函数。 8 | 9 | - `options`:(默认值:`null`)选项对象。也可以是一个 `Ref` 、一个响应式对象或是一个返回选项对象的函数。 10 | 11 | - `clientId`:当提供了多个客户端时,指定使用的客户端 ID。 12 | 13 | - `debounce`:防抖间隔毫秒数。 14 | 15 | - `enabled`:布尔值 `Ref`,用于启用或禁用查询。 16 | 17 | - `fetchPolicy`:自定义缓存行为。 18 | - `cache-first`(默认):从缓存返回结果。仅当无法获得缓存结果时才从网络获取。 19 | - `cache-and-network`:首先从缓存中返回结果(如果存在),然后在网络可用时返回网络结果。 20 | - `cache-only`:从缓存返回结果(如果可用),否则失败。 21 | - `network-only`:从网络返回结果并保存到缓存,如果网络调用未成功则失败。 22 | - `no-cache`:从网络返回结果但不保存到缓存,如果网络调用未成功则失败。 23 | 24 | - `throttle`:节流间隔毫秒数。 25 | 26 | ## 返回值 27 | 28 | - `result`:结果数据对象。 29 | 30 | - `loading`:布尔值 Ref,当订阅正在进行中时为 `true`。 31 | 32 | - `error`:Error Ref,保存任何发生的错误。 33 | 34 | - `variables`:Ref,保存变量对象。 35 | 36 | - `onResult(handler)`:有新结果可用时调用的事件钩子。 37 | 38 | - `onError(handler)`:发生错误时调用的事件钩子。 39 | -------------------------------------------------------------------------------- /packages/docs/src/zh-cn/guide-advanced/index.md: -------------------------------------------------------------------------------- 1 | # 简介 2 | 3 | 这一部分指南是进阶主题文章的集合。 4 | -------------------------------------------------------------------------------- /packages/docs/src/zh-cn/guide-components/index.md: -------------------------------------------------------------------------------- 1 | # 简介 2 | 3 | ## 什么是 Apollo 组件? 4 | 5 | 这些组件就像其他组件一样。它们在 prop 中使用 GraphQL 文档,并使用 [作用域插槽功能](https://vuejs.org/v2/guide/components-slots.html#Scoped-Slots) 来传递结果。 6 | 7 | 这样做的好处是你可以直接在模板中使用这些组件,而不是使用组件的 `apollo` 选项。在某些情况下,你甚至不需要在 `.vue` 中添加脚本部分!这种代码会更加声明式。 8 | 9 | 这是一个模板中 [ApolloQuery](./query.md) 的简单示例: 10 | 11 | ```vue 12 | 27 | 28 | 29 | ``` 30 | -------------------------------------------------------------------------------- /packages/docs/src/zh-cn/guide-components/setup.md: -------------------------------------------------------------------------------- 1 | # Setup 2 | 3 | 确保你已经 [安装了 Apollo Client](../guide/installation.md)。 4 | 5 | ## 1. 安装 @vue/apollo-components 6 | 7 | ``` 8 | npm install --save @vue/apollo-option @vue/apollo-components 9 | ``` 10 | 11 | 或: 12 | 13 | ``` 14 | yarn add @vue/apollo-option @vue/apollo-components 15 | ``` 16 | 17 | ## 2. Create the Apollo client 18 | 19 | ```js 20 | import { ApolloClient, InMemoryCache } from '@apollo/client/core' 21 | 22 | const cache = new InMemoryCache() 23 | 24 | const apolloClient = new ApolloClient({ 25 | cache, 26 | uri: 'http://localhost:4042/graphql', 27 | }) 28 | ``` 29 | 30 | ::: warning 31 | Use the `@apollo/client/core` import path otherwise you will also import React. 32 | ::: 33 | 34 | ## 3. Create the Apollo provider 35 | 36 | The provider holds the Apollo client instances that can then be used by all the child components. 37 | 38 | ```js 39 | const apolloProvider = createApolloProvider({ 40 | defaultClient: apolloClient, 41 | }) 42 | ``` 43 | ## 4. Add the provider to your app 44 | 45 | Add it to your app with the `app.use` function: 46 | 47 | ```js 48 | import { createApp, h } from 'vue' 49 | 50 | const app = createApp({ 51 | render: () => h(App), 52 | }) 53 | 54 | app.use(apolloProvider) 55 | ``` 56 | 57 | ## 5. Add the components to your app 58 | 59 | ```js 60 | import VueApolloComponents from '@vue/apollo-components' 61 | 62 | // ... 63 | 64 | app.use(VueApolloComponents) 65 | ``` 66 | 67 | 现在你已经完成了在组件中使用 Apollo 的所有准备了! 68 | -------------------------------------------------------------------------------- /packages/docs/src/zh-cn/guide-composable/cache-interaction.md: -------------------------------------------------------------------------------- 1 | # 与缓存的数据进行交互 2 | 3 | 当前章节尚未完成。 4 | 5 | 在此期间,可参阅 [react apollo 文档](https://www.apollographql.com/docs/react/caching/cache-interaction/)。 6 | -------------------------------------------------------------------------------- /packages/docs/src/zh-cn/guide-composable/index.md: -------------------------------------------------------------------------------- 1 | # 简介 2 | 3 | 组合 API 是一种让你可以在 `setup` 选项中的以容易组合的方式编写数据和逻辑的 API。 4 | 5 | 如果你正在使用 Typescript,强烈建议开始使用组合 API,因为它的类型能力是任何其他 Vue API 都无法比拟的。 6 | 7 | [在这里](https://vue-composition-api-rfc.netlify.com/) 了解更多关于组合 API 的信息。 8 | 9 | 这里是一个使用该 API 的示例: 10 | 11 | ```vue 12 | 26 | ``` 27 | -------------------------------------------------------------------------------- /packages/docs/src/zh-cn/guide-composable/setup.md: -------------------------------------------------------------------------------- 1 | # Setup 2 | 3 | 确保你已经 [安装了 Apollo Client](../guide/installation.md)。 4 | 5 | ## 1. 安装 @vue/apollo-composable 6 | 7 | ```shell 8 | npm install --save @vue/apollo-composable 9 | ``` 10 | 11 | 或: 12 | 13 | ```shell 14 | yarn add @vue/apollo-composable 15 | ``` 16 | 17 | ## 2. 连接 Apollo Client 到 Vue 18 | 19 | 你需要在根实例中提供一个默认的 Apollo Client 实例: 20 | 21 | ```js 22 | import { DefaultApolloClient } from '@vue/apollo-composable' 23 | import { provide } from 'vue' 24 | 25 | const app = new Vue({ 26 | setup() { 27 | provide(DefaultApolloClient, apolloClient) 28 | }, 29 | 30 | render: h => h(App), 31 | }) 32 | ``` 33 | 34 | ### 多客户端 35 | 36 | 你也可以提供为应用提供多个可用的 Apollo Client 实例。在这种情况下,建议提供一个 `default` 值: 37 | 38 | ```js 39 | import { ApolloClients } from '@vue/apollo-composable' 40 | import { provide } from 'vue' 41 | 42 | const app = new Vue({ 43 | setup() { 44 | provide(ApolloClients, { 45 | default: apolloClient, 46 | }) 47 | }, 48 | 49 | render: h => h(App), 50 | }) 51 | ``` 52 | 53 | 你可以在旁边添加其他客户端实例: 54 | 55 | ```js 56 | provide(ApolloClients, { 57 | default: apolloClient, 58 | clientA: apolloClientA, 59 | clientB: apolloClientB, 60 | }) 61 | ``` 62 | 63 | 然后,你可以在函数中通过 `clientId` 选项来选择其中的一个使用(例如`useQuery`、`useMutation` 和 `useSubscription`)。 64 | -------------------------------------------------------------------------------- /packages/docs/src/zh-cn/guide-option/index.md: -------------------------------------------------------------------------------- 1 | # 简介 2 | 3 | 选项 API 基于 `apollo` Vue 组件选项。 4 | 5 | 示例: 6 | 7 | ```vue 8 | 15 | ``` 16 | -------------------------------------------------------------------------------- /packages/docs/src/zh-cn/guide-option/setup.md: -------------------------------------------------------------------------------- 1 | # Setup 2 | 3 | 确保你已经 [安装了 Apollo Client](../guide/installation.md)。 4 | 5 | ## 1. 安装 @vue/apollo-option 6 | 7 | ``` 8 | npm install --save @vue/apollo-option 9 | ``` 10 | 11 | 或: 12 | 13 | ``` 14 | yarn add @vue/apollo-option 15 | ``` 16 | 17 | ## 2. Create the Apollo client 18 | 19 | ```js 20 | import { ApolloClient, InMemoryCache } from '@apollo/client/core' 21 | 22 | const cache = new InMemoryCache() 23 | 24 | const apolloClient = new ApolloClient({ 25 | cache, 26 | uri: 'http://localhost:4042/graphql', 27 | }) 28 | ``` 29 | 30 | ::: warning 31 | Use the `@apollo/client/core` import path otherwise you will also import React. 32 | ::: 33 | 34 | ## 3. 注入 Apollo provider 35 | 36 | Provider 保存了可以在接下来被所有子组件使用的 Apollo 客户端实例。 37 | 38 | ```js 39 | import { createApolloProvider } from '@vue/apollo-option' 40 | 41 | const apolloProvider = createApolloProvider({ 42 | defaultClient: apolloClient, 43 | }) 44 | ``` 45 | 46 | ## 4. Add the provider to your app 47 | 48 | 使用 `apolloProvider` 选项将它添加到你的应用程序: 49 | 50 | ```js 51 | import { createApp, h } from 'vue' 52 | 53 | const app = createApp({ 54 | render: () => h(App), 55 | }) 56 | 57 | app.use(apolloProvider) 58 | ``` 59 | 60 | 现在你已经完成了在组件中使用 Apollo 的所有准备了! 61 | -------------------------------------------------------------------------------- /packages/docs/src/zh-cn/guide-option/usage.md: -------------------------------------------------------------------------------- 1 | # 在 Vue 组件中的用法 2 | 3 | 在你的应用中安装了 `vue-apollo` 之后,所有组件都可以通过 `apollo` 这一特殊选项来使用 Apollo。 4 | 5 | ## `apollo` 选项 6 | 7 | 要在你的 Vue 组件中声明 apollo 查询,在组件的选项中添加 `apollo` 对象: 8 | 9 | ```js 10 | new Vue({ 11 | apollo: { 12 | // Apollo 的具体选项 13 | }, 14 | }) 15 | ``` 16 | 17 | 在一个 `.vue` 文件中: 18 | 19 | ```vue 20 | 23 | 24 | 31 | ``` 32 | 33 | ## 特殊选项 34 | 35 | `apollo` 对象中的特殊选项以 `$` 开头表示。 36 | 37 | 请查看 [特殊选项](./special-options.md) 一章以了解更多。 38 | 39 | ## `$apollo` 40 | 41 | 在一个有着 `apolloProvider` 选项的组件之下的所有组件都可以使用一个 `$apollo` 辅助函数。这是你的组件和 Apollo 之间的胶水层,它可以为你完成所有繁重的工作(包括自动更新和销毁)。 42 | 43 | 在你的每个 vue 组件中,你都可以通过 `this.$apollo.provider.defaultClient` 或 `this.$apollo.provider.clients.`(用于 [多客户端](./multiple-clients.md))来访问 [apollo-client](https://www.apollographql.com/docs/react/) 实例。 44 | 45 | 如果你很好奇,请查看 [$apollo API](../api/dollar-apollo.md)。 46 | -------------------------------------------------------------------------------- /packages/docs/src/zh-cn/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | home: true 3 | sidebar: false 4 | heroImage: /logo.png 5 | actionText: 由此起步 → 6 | actionLink: /zh-cn/guide/ 7 | features: 8 | - title: 自动更新 9 | details: 无需考虑更新 UI 或重新获取查询的问题! 10 | - title: 模板内组件 11 | details: 通过 Apollo 组件声明式地使用 Apollo 12 | - title: 支持 SSR 13 | details: 在渲染 HTML 页面之前在服务端运行你的查询 14 | footer: LICENCE MIT - Created by Guillaume CHAU (@Akryum) 15 | --- 16 | 17 | 18 | 19 | ## 赞助商 20 | 21 |

22 | 23 | 24 | 25 |

26 | 27 | ::: tip 当前版本 28 | 中文文档现在同步至 v4.0.0-alpha.12 29 | ::: 30 | -------------------------------------------------------------------------------- /packages/docs/src/zh-cn/migration/index.md: -------------------------------------------------------------------------------- 1 | # 从 vue-apollo 3 迁移 2 | 3 | 当前章节尚未完成。 4 | -------------------------------------------------------------------------------- /packages/test-e2e-composable-vue3/.browserslistrc: -------------------------------------------------------------------------------- 1 | > 1% 2 | last 2 versions 3 | not dead 4 | -------------------------------------------------------------------------------- /packages/test-e2e-composable-vue3/.editorconfig: -------------------------------------------------------------------------------- 1 | [*.{js,jsx,ts,tsx,vue}] 2 | indent_style = space 3 | indent_size = 2 4 | trim_trailing_whitespace = true 5 | insert_final_newline = true 6 | -------------------------------------------------------------------------------- /packages/test-e2e-composable-vue3/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | 5 | /tests/e2e/videos/ 6 | /tests/e2e/screenshots/ 7 | /tests/e2e/downloads/ 8 | 9 | 10 | # local env files 11 | .env.local 12 | .env.*.local 13 | 14 | # Log files 15 | npm-debug.log* 16 | yarn-debug.log* 17 | yarn-error.log* 18 | pnpm-debug.log* 19 | 20 | # Editor directories and files 21 | .idea 22 | .vscode 23 | *.suo 24 | *.ntvs* 25 | *.njsproj 26 | *.sln 27 | *.sw? 28 | -------------------------------------------------------------------------------- /packages/test-e2e-composable-vue3/README.md: -------------------------------------------------------------------------------- 1 | # test-e2e-global-composable-vue3 2 | 3 | ## Project setup 4 | ``` 5 | pnpm install 6 | ``` 7 | 8 | ### Compiles and hot-reloads for development 9 | ``` 10 | pnpm run serve 11 | ``` 12 | 13 | ### Compiles and minifies for production 14 | ``` 15 | pnpm run build 16 | ``` 17 | 18 | ### Run your end-to-end tests 19 | ``` 20 | pnpm run test:e2e 21 | ``` 22 | 23 | ### Customize configuration 24 | See [Configuration Reference](https://cli.vuejs.org/config/). 25 | -------------------------------------------------------------------------------- /packages/test-e2e-composable-vue3/cypress.config.ts: -------------------------------------------------------------------------------- 1 | import axios from 'axios' 2 | import { defineConfig } from 'cypress' 3 | import vitePreprocessor from 'cypress-vite' 4 | 5 | export default defineConfig({ 6 | fixturesFolder: 'tests/e2e/fixtures', 7 | screenshotsFolder: 'tests/e2e/screenshots', 8 | videosFolder: 'tests/e2e/videos', 9 | downloadsFolder: 'tests/e2e/downloads', 10 | e2e: { 11 | baseUrl: 'http://localhost:8080', 12 | // We've imported your old cypress plugins here. 13 | // You may want to clean this up later by importing these. 14 | setupNodeEvents(on) { 15 | on('task', { 16 | 'db:reset': async function () { 17 | await axios.get('http://localhost:4042/_reset') 18 | return true 19 | }, 20 | }) 21 | on('file:preprocessor', vitePreprocessor()) 22 | }, 23 | specPattern: 'tests/e2e/specs/**/*.cy.{js,jsx,ts,tsx}', 24 | supportFile: 'tests/e2e/support/index.ts', 25 | }, 26 | }) 27 | -------------------------------------------------------------------------------- /packages/test-e2e-composable-vue3/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 12 |
13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /packages/test-e2e-composable-vue3/postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /packages/test-e2e-composable-vue3/src/apollo.ts: -------------------------------------------------------------------------------- 1 | import { ApolloClient, createHttpLink, InMemoryCache, split } from '@apollo/client/core' 2 | import { onError } from '@apollo/client/link/error' 3 | import { GraphQLWsLink } from '@apollo/client/link/subscriptions' 4 | import { getMainDefinition } from '@apollo/client/utilities' 5 | import { logErrorMessages } from '@vue/apollo-util' 6 | import { createClient } from 'graphql-ws' 7 | 8 | const cache = new InMemoryCache() 9 | 10 | // HTTP connection to the API 11 | const httpLink = createHttpLink({ 12 | // You should use an absolute URL here 13 | uri: 'http://localhost:4042/graphql', 14 | }) 15 | 16 | const wsLink = new GraphQLWsLink(createClient({ 17 | url: 'ws://localhost:4042/graphql', 18 | })) 19 | 20 | const splitLink = split( 21 | ({ query }) => { 22 | const definition = getMainDefinition(query) 23 | if (definition.kind === 'OperationDefinition' 24 | && definition.operation === 'subscription') { 25 | console.log(`Subscribing to ${definition.name?.value ?? 'anonymous'}`) 26 | } 27 | return ( 28 | definition.kind === 'OperationDefinition' 29 | && definition.operation === 'subscription' 30 | ) 31 | }, 32 | wsLink, 33 | httpLink, 34 | ) 35 | 36 | // Handle errors 37 | const errorLink = onError((error) => { 38 | logErrorMessages(error) 39 | }) 40 | 41 | export const apolloClient = new ApolloClient({ 42 | cache, 43 | link: errorLink.concat(splitLink), 44 | }) 45 | -------------------------------------------------------------------------------- /packages/test-e2e-composable-vue3/src/assets/styles/tailwind.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | 3 | @tailwind components; 4 | 5 | @tailwind utilities; 6 | -------------------------------------------------------------------------------- /packages/test-e2e-composable-vue3/src/components/App.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 22 | -------------------------------------------------------------------------------- /packages/test-e2e-composable-vue3/src/components/ChannelList.vue: -------------------------------------------------------------------------------- 1 | 25 | 26 | 63 | -------------------------------------------------------------------------------- /packages/test-e2e-composable-vue3/src/components/ChannelListPinia.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 44 | -------------------------------------------------------------------------------- /packages/test-e2e-composable-vue3/src/components/ChannelListPinia2.vue: -------------------------------------------------------------------------------- 1 | 21 | 22 | 52 | -------------------------------------------------------------------------------- /packages/test-e2e-composable-vue3/src/components/ChannelListPiniaContainer.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 26 | -------------------------------------------------------------------------------- /packages/test-e2e-composable-vue3/src/components/GlobalLoading.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 17 | -------------------------------------------------------------------------------- /packages/test-e2e-composable-vue3/src/components/LazyQuery.vue: -------------------------------------------------------------------------------- 1 | 24 | 25 | 58 | -------------------------------------------------------------------------------- /packages/test-e2e-composable-vue3/src/components/LazyQueryImmediately.vue: -------------------------------------------------------------------------------- 1 | 34 | 35 | 50 | -------------------------------------------------------------------------------- /packages/test-e2e-composable-vue3/src/components/LazyQueryLoad.vue: -------------------------------------------------------------------------------- 1 | 21 | 22 | 41 | -------------------------------------------------------------------------------- /packages/test-e2e-composable-vue3/src/components/LazyQueryLoadError.vue: -------------------------------------------------------------------------------- 1 | 28 | 29 | 55 | -------------------------------------------------------------------------------- /packages/test-e2e-composable-vue3/src/components/MessageItem.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 21 | -------------------------------------------------------------------------------- /packages/test-e2e-composable-vue3/src/components/NoSetupQuery.vue: -------------------------------------------------------------------------------- 1 | 24 | 25 | 30 | -------------------------------------------------------------------------------- /packages/test-e2e-composable-vue3/src/components/NoSetupQueryMultiClient.vue: -------------------------------------------------------------------------------- 1 | 30 | 31 | 36 | -------------------------------------------------------------------------------- /packages/test-e2e-composable-vue3/src/components/NoSetupScopeQuery.vue: -------------------------------------------------------------------------------- 1 | 37 | 38 | 43 | -------------------------------------------------------------------------------- /packages/test-e2e-composable-vue3/src/components/OnResult.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 25 | -------------------------------------------------------------------------------- /packages/test-e2e-composable-vue3/src/components/OnResultChild.vue: -------------------------------------------------------------------------------- 1 | 27 | 28 | 46 | -------------------------------------------------------------------------------- /packages/test-e2e-composable-vue3/src/components/PartialError.vue: -------------------------------------------------------------------------------- 1 | 30 | 31 | 49 | -------------------------------------------------------------------------------- /packages/test-e2e-composable-vue3/src/components/Subscription.vue: -------------------------------------------------------------------------------- 1 | 22 | 23 | 38 | -------------------------------------------------------------------------------- /packages/test-e2e-composable-vue3/src/components/Subscriptions.vue: -------------------------------------------------------------------------------- 1 | 5 | 6 | 21 | -------------------------------------------------------------------------------- /packages/test-e2e-composable-vue3/src/components/Welcome.vue: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /packages/test-e2e-composable-vue3/src/main.ts: -------------------------------------------------------------------------------- 1 | import { DefaultApolloClient } from '@vue/apollo-composable' 2 | import { createPinia } from 'pinia' 3 | import { createApp } from 'vue' 4 | import { apolloClient } from './apollo' 5 | import App from './components/App.vue' 6 | import { router } from './router' 7 | import '@/assets/styles/tailwind.css' 8 | 9 | const app = createApp(App) 10 | app.use(createPinia()) 11 | app.use(router) 12 | app.provide(DefaultApolloClient, apolloClient) 13 | app.mount('#app') 14 | -------------------------------------------------------------------------------- /packages/test-e2e-composable-vue3/src/shims-vue.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.vue' { 2 | import type { DefineComponent } from 'vue' 3 | 4 | const component: DefineComponent 5 | export default component 6 | } 7 | -------------------------------------------------------------------------------- /packages/test-e2e-composable-vue3/src/stores/channel.ts: -------------------------------------------------------------------------------- 1 | import { useQuery } from '@vue/apollo-composable' 2 | import gql from 'graphql-tag' 3 | import { defineStore } from 'pinia' 4 | import { computed, watch } from 'vue' 5 | 6 | interface Channel { 7 | id: string 8 | label: string 9 | } 10 | 11 | export const useChannels = defineStore('channel', () => { 12 | const query = useQuery<{ channels: Channel[] }>(gql` 13 | query channels { 14 | channels { 15 | id 16 | label 17 | } 18 | } 19 | `) 20 | 21 | const channels = computed(() => query.result.value?.channels ?? []) 22 | 23 | watch(query.loading, (value) => { 24 | console.log('loading', value) 25 | }, { 26 | immediate: true, 27 | }) 28 | 29 | return { 30 | loading: query.loading, 31 | channels, 32 | } 33 | }) 34 | -------------------------------------------------------------------------------- /packages/test-e2e-composable-vue3/tailwind.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('tailwindcss').Config} */ 2 | module.exports = { 3 | content: ['./index.html', './src/**/*.{vue,js,ts,jsx,tsx}'], 4 | theme: { 5 | extend: {}, 6 | }, 7 | plugins: [], 8 | } 9 | -------------------------------------------------------------------------------- /packages/test-e2e-composable-vue3/tests/e2e/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: [ 3 | 'cypress', 4 | ], 5 | env: { 6 | 'mocha': true, 7 | 'cypress/globals': true, 8 | }, 9 | rules: { 10 | strict: 'off', 11 | }, 12 | } 13 | -------------------------------------------------------------------------------- /packages/test-e2e-composable-vue3/tests/e2e/specs/errorPolicy.cy.ts: -------------------------------------------------------------------------------- 1 | describe('errorPolicy', () => { 2 | it('supports `errorPolicy` option', () => { 3 | cy.visit('/partial-error') 4 | 5 | // All 6 | cy.get('.all .result').should('contain', '"good": "good"').should('contain', '"bad": null') 7 | cy.get('.all .error').should('contain', 'Error: GraphQL response contains errors: An error') 8 | 9 | // None 10 | cy.get('.none .result').should('not.contain', 'good').should('not.contain', 'bad') 11 | cy.get('.none .error').should('contain', 'Error: An error') 12 | 13 | // Ignore 14 | cy.get('.ignore .result').should('contain', '"good": "good"').should('contain', '"bad": null') 15 | cy.get('.ignore .error').should('not.exist') 16 | }) 17 | }) 18 | -------------------------------------------------------------------------------- /packages/test-e2e-composable-vue3/tests/e2e/specs/keepPreviousResult.cy.ts: -------------------------------------------------------------------------------- 1 | describe('keepPreviousResult', () => { 2 | beforeEach(() => { 3 | cy.task('db:reset') 4 | cy.visit('/keep-previous-result') 5 | }) 6 | 7 | it('keepPreviousResult disabled: should clear previous data', () => { 8 | cy.get('.no-data').should('be.visible') 9 | cy.get('.channel-btn').eq(0).click() 10 | cy.get('.no-data').should('be.visible') 11 | cy.get('.the-channel').should('contain.text', '# General') 12 | cy.get('.no-data').should('not.exist') 13 | cy.get('.channel-btn').eq(1).click() 14 | cy.get('.no-data').should('be.visible') 15 | cy.get('.the-channel').should('contain.text', '# Random') 16 | cy.get('.no-data').should('not.exist') 17 | }) 18 | 19 | it('keepPreviousResult enabled: should display previous channel', () => { 20 | cy.get('label').contains('keepPreviousResult').get('input[type="checkbox"]').check() 21 | cy.get('.no-data').should('be.visible') 22 | cy.get('.channel-btn').eq(0).click() 23 | cy.get('.no-data').should('be.visible') 24 | cy.get('.the-channel').should('contain.text', '# General') 25 | cy.get('.no-data').should('not.exist') 26 | cy.get('.channel-btn').eq(1).click() 27 | cy.get('.no-data').should('not.exist') 28 | cy.get('.the-channel').should('contain.text', '# General') 29 | cy.get('.the-channel').should('contain.text', '# Random') 30 | }) 31 | }) 32 | -------------------------------------------------------------------------------- /packages/test-e2e-composable-vue3/tests/e2e/specs/nullableQuery.cy.ts: -------------------------------------------------------------------------------- 1 | describe('nullableQuery', () => { 2 | beforeEach(() => { 3 | cy.task('db:reset') 4 | cy.visit('/null-query') 5 | }) 6 | 7 | it('should enable useQuery only if query is non-null', () => { 8 | cy.get('button').should('exist') 9 | cy.wait(100) 10 | cy.get('[data-test-id="data"]').should('not.exist') 11 | cy.get('.loading').should('not.exist') 12 | cy.get('button').click() 13 | cy.get('[data-test-id="data"]').should('contain', 'Loaded channel: General') 14 | }) 15 | }) 16 | -------------------------------------------------------------------------------- /packages/test-e2e-composable-vue3/tests/e2e/specs/outsideComponent.cy.ts: -------------------------------------------------------------------------------- 1 | describe('Query outside of component', () => { 2 | beforeEach(() => { 3 | cy.task('db:reset') 4 | cy.visit('/') 5 | }) 6 | 7 | it('supports queries outside of setup', () => { 8 | cy.visit('/no-setup-query') 9 | cy.contains('.no-setup-query', 'Hello world!') 10 | }) 11 | 12 | it('supports queries outside of setup with multiple clients', () => { 13 | cy.visit('/no-setup-query-multi-client') 14 | cy.contains('.no-setup-query', 'Hello world!') 15 | }) 16 | 17 | it('supports queries outside of setup but within scope', () => { 18 | cy.visit('/no-setup-scope-query') 19 | cy.contains('.no-setup-scope-query', 'Hello world!') 20 | }) 21 | }) 22 | -------------------------------------------------------------------------------- /packages/test-e2e-composable-vue3/tests/e2e/specs/pinia.cy.ts: -------------------------------------------------------------------------------- 1 | describe('Pinia', () => { 2 | beforeEach(() => { 3 | cy.task('db:reset') 4 | }) 5 | 6 | it('with current instance', () => { 7 | cy.visit('/pinia') 8 | cy.get('.channel-link').should('have.lengthOf', 2) 9 | cy.contains('.channel-link', '# General') 10 | cy.contains('.channel-link', '# Random') 11 | }) 12 | 13 | it('with effect scope only', () => { 14 | cy.visit('/pinia2') 15 | cy.get('.channel-link').should('have.lengthOf', 2) 16 | cy.contains('.channel-link', '# General') 17 | cy.contains('.channel-link', '# Random') 18 | }) 19 | 20 | it('works after component unmount if used in pinia', () => { 21 | cy.visit('/pinia3') 22 | cy.get('[data-test-id="channel-list-container"]').should('exist') 23 | cy.get('[data-test-id="channel-list-toggle"]').first().click() 24 | cy.get('[data-test-id="channel-list-container"]').should('not.exist') 25 | cy.get('[data-test-id="channel-list-toggle"]').first().click() 26 | cy.get('.channel-link').should('have.lengthOf', 2) 27 | cy.contains('.channel-link', '# General') 28 | cy.contains('.channel-link', '# Random') 29 | }) 30 | }) 31 | -------------------------------------------------------------------------------- /packages/test-e2e-composable-vue3/tests/e2e/specs/subscription.cy.ts: -------------------------------------------------------------------------------- 1 | describe('Subscription', () => { 2 | beforeEach(() => { 3 | cy.task('db:reset') 4 | cy.visit('/') 5 | }) 6 | 7 | it('receive messages in real time', () => { 8 | cy.visit('/subscriptions') 9 | cy.get('input').type('Meow{enter}') 10 | cy.get('.message').should('have.length', 3) 11 | cy.get('.message').should('contain', 'Meow') 12 | cy.get('input').should('have.value', '') 13 | cy.get('input').type('Waf{enter}') 14 | cy.get('.message').should('have.length', 6) 15 | cy.get('.message').should('contain', 'Waf') 16 | }) 17 | }) 18 | -------------------------------------------------------------------------------- /packages/test-e2e-composable-vue3/tests/e2e/specs/updateQuery.cy.ts: -------------------------------------------------------------------------------- 1 | describe('updateQuery', () => { 2 | beforeEach(() => { 3 | cy.task('db:reset') 4 | cy.visit('/update-query') 5 | }) 6 | 7 | it('should add new message to cache using updateQuery', () => { 8 | cy.get('.channel-btn').eq(0).click() 9 | cy.get('.message-input').type('hello 1') 10 | cy.get('.message').should('have.lengthOf', 0) 11 | cy.get('.send-message-btn').click() 12 | cy.get('.message').should('have.lengthOf', 1) 13 | cy.get('.message-input').type('hello 2') 14 | cy.get('.send-message-btn').click() 15 | cy.get('.message').should('have.lengthOf', 2) 16 | cy.contains('.message', 'hello 1') 17 | cy.contains('.message', 'hello 2') 18 | 19 | cy.get('.channel-btn').eq(1).click() 20 | cy.get('.message-input').type('hello 3') 21 | cy.get('.message').should('have.lengthOf', 0) 22 | cy.get('.send-message-btn').click() 23 | cy.get('.message').should('have.lengthOf', 1) 24 | cy.get('.message-input').type('hello 4') 25 | cy.get('.send-message-btn').click() 26 | cy.get('.message').should('have.lengthOf', 2) 27 | cy.contains('.message', 'hello 3') 28 | cy.contains('.message', 'hello 4') 29 | }) 30 | }) 31 | -------------------------------------------------------------------------------- /packages/test-e2e-composable-vue3/tests/e2e/support/commands.ts: -------------------------------------------------------------------------------- 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 is will overwrite an existing command -- 25 | // Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... }) 26 | -------------------------------------------------------------------------------- /packages/test-e2e-composable-vue3/tests/e2e/support/index.ts: -------------------------------------------------------------------------------- 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/test-e2e-composable-vue3/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "esnext", 4 | "jsx": "preserve", 5 | "lib": [ 6 | "esnext", 7 | "dom", 8 | "dom.iterable", 9 | "scripthost" 10 | ], 11 | "baseUrl": ".", 12 | "module": "esnext", 13 | "moduleResolution": "node", 14 | "paths": { 15 | "@/*": [ 16 | "src/*" 17 | ] 18 | }, 19 | "types": [ 20 | "vite/client", 21 | "cypress" 22 | ], 23 | "strict": true, 24 | "importHelpers": true, 25 | "sourceMap": true, 26 | "allowSyntheticDefaultImports": true, 27 | "esModuleInterop": true, 28 | "skipLibCheck": true 29 | }, 30 | "include": [ 31 | "src/**/*.ts", 32 | "src/**/*.tsx", 33 | "src/**/*.vue", 34 | "tests/**/*.ts", 35 | "tests/**/*.tsx" 36 | ], 37 | "exclude": [ 38 | "node_modules" 39 | ] 40 | } 41 | -------------------------------------------------------------------------------- /packages/test-e2e-composable-vue3/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { resolve } from 'node:path' 2 | import vue from '@vitejs/plugin-vue' 3 | import { defineConfig } from 'vite' 4 | 5 | // https://vitejs.dev/config/ 6 | export default defineConfig({ 7 | plugins: [vue()], 8 | resolve: { 9 | alias: { 10 | '@': resolve(__dirname, './src'), 11 | }, 12 | }, 13 | }) 14 | -------------------------------------------------------------------------------- /packages/test-e2e-ssr/.browserslistrc: -------------------------------------------------------------------------------- 1 | > 1% 2 | last 2 versions 3 | not dead 4 | -------------------------------------------------------------------------------- /packages/test-e2e-ssr/.editorconfig: -------------------------------------------------------------------------------- 1 | [*.{js,jsx,ts,tsx,vue}] 2 | indent_style = space 3 | indent_size = 2 4 | trim_trailing_whitespace = true 5 | insert_final_newline = true 6 | -------------------------------------------------------------------------------- /packages/test-e2e-ssr/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | 5 | /tests/e2e/videos/ 6 | /tests/e2e/screenshots/ 7 | /tests/e2e/downloads/ 8 | 9 | 10 | # local env files 11 | .env.local 12 | .env.*.local 13 | 14 | # Log files 15 | npm-debug.log* 16 | yarn-debug.log* 17 | yarn-error.log* 18 | pnpm-debug.log* 19 | 20 | # Editor directories and files 21 | .idea 22 | .vscode 23 | *.suo 24 | *.ntvs* 25 | *.njsproj 26 | *.sln 27 | *.sw? 28 | -------------------------------------------------------------------------------- /packages/test-e2e-ssr/README.md: -------------------------------------------------------------------------------- 1 | # test-e2e-global-composable-vue3 2 | 3 | ## Project setup 4 | ``` 5 | pnpm install 6 | ``` 7 | 8 | ### Compiles and hot-reloads for development 9 | ``` 10 | pnpm run serve 11 | ``` 12 | 13 | ### Compiles and minifies for production 14 | ``` 15 | pnpm run build 16 | ``` 17 | 18 | ### Run your end-to-end tests 19 | ``` 20 | pnpm run test:e2e 21 | ``` 22 | 23 | ### Customize configuration 24 | See [Configuration Reference](https://cli.vuejs.org/config/). 25 | -------------------------------------------------------------------------------- /packages/test-e2e-ssr/cypress.config.ts: -------------------------------------------------------------------------------- 1 | import axios from 'axios' 2 | import { defineConfig } from 'cypress' 3 | import vitePreprocessor from 'cypress-vite' 4 | 5 | export default defineConfig({ 6 | fixturesFolder: 'tests/e2e/fixtures', 7 | screenshotsFolder: 'tests/e2e/screenshots', 8 | videosFolder: 'tests/e2e/videos', 9 | downloadsFolder: 'tests/e2e/downloads', 10 | e2e: { 11 | baseUrl: 'http://localhost:8080', 12 | // We've imported your old cypress plugins here. 13 | // You may want to clean this up later by importing these. 14 | setupNodeEvents(on) { 15 | on('task', { 16 | 'db:reset': async function () { 17 | await axios.get('http://localhost:4042/_reset') 18 | return true 19 | }, 20 | 21 | 'db:seed': async function () { 22 | await axios.get('http://localhost:4042/_seed') 23 | return true 24 | }, 25 | }) 26 | on('file:preprocessor', vitePreprocessor()) 27 | }, 28 | specPattern: 'tests/e2e/specs/**/*.cy.{js,jsx,ts,tsx}', 29 | supportFile: 'tests/e2e/support/index.ts', 30 | }, 31 | }) 32 | -------------------------------------------------------------------------------- /packages/test-e2e-ssr/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | My app 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /packages/test-e2e-ssr/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "test-e2e-ssr", 3 | "version": "4.0.0-alpha.16", 4 | "private": true, 5 | "scripts": { 6 | "dev": "node ./server.mjs", 7 | "test": "pnpm run test:e2e", 8 | "test:e2e": "start-server-and-test api 'http-get://localhost:4042/graphql?query=%7B__typename%7D' test:e2e:run", 9 | "test:e2e:run": "start-server-and-test dev http://localhost:8080 test:e2e:cy", 10 | "test:e2e:cy": "cypress run --headless", 11 | "test:e2e:dev": "cypress open", 12 | "api": "test-server --simulate-latency 50", 13 | "api:dev": "test-server --simulate-latency 500" 14 | }, 15 | "dependencies": { 16 | "@apollo/client": "^3.7.16", 17 | "@vue/apollo-composable": "workspace:*", 18 | "@vue/apollo-util": "workspace:*", 19 | "devalue": "^4.3.2", 20 | "express": "^4.18.2", 21 | "graphql": "^16.7.1", 22 | "graphql-tag": "^2.12.6", 23 | "isomorphic-fetch": "^3.0.0", 24 | "test-server": "workspace:*", 25 | "vue": "^3.3.4", 26 | "vue-router": "^4.2.4" 27 | }, 28 | "devDependencies": { 29 | "@types/node": "^20.6.0", 30 | "@vitejs/plugin-vue": "^4.2.3", 31 | "autoprefixer": "^10.4.14", 32 | "axios": "^1.4.0", 33 | "cypress": "^12.17.0", 34 | "cypress-vite": "^1.4.1", 35 | "postcss": "^8.4.25", 36 | "start-server-and-test": "^2.0.0", 37 | "tailwindcss": "^3.3.2", 38 | "typescript": "^5.0.2", 39 | "vite": "^4.4.2", 40 | "vue-tsc": "^1.8.3" 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /packages/test-e2e-ssr/postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /packages/test-e2e-ssr/server.mjs: -------------------------------------------------------------------------------- 1 | import fs from 'node:fs' 2 | import { uneval } from 'devalue' 3 | import express from 'express' 4 | import { createServer } from 'vite' 5 | 6 | const server = express() 7 | 8 | const viteServer = await createServer({ 9 | server: { 10 | middlewareMode: true, 11 | }, 12 | appType: 'custom', 13 | }) 14 | server.use(viteServer.middlewares) 15 | 16 | server.get('*', async (req, res) => { 17 | try { 18 | const url = req.originalUrl 19 | console.log(url) 20 | 21 | let template = fs.readFileSync('./index.html', 'utf8') 22 | 23 | const { render } = await viteServer.ssrLoadModule('/src/entry-server.ts') 24 | const { html, context } = await render(url) 25 | 26 | console.log(context) 27 | 28 | template = template 29 | .replace('', uneval(context.state)) 30 | .replace('', html) 31 | 32 | res.send(template) 33 | } 34 | catch (e) { 35 | console.error(e) 36 | res.send(e.stack) 37 | } 38 | }) 39 | 40 | server.use(express.static('.')) 41 | 42 | server.listen(8080, () => { 43 | console.log('Server is running on http://localhost:8080') 44 | }) 45 | -------------------------------------------------------------------------------- /packages/test-e2e-ssr/src/apollo.ts: -------------------------------------------------------------------------------- 1 | import { ApolloClient, createHttpLink, InMemoryCache } from '@apollo/client/core' 2 | import { onError } from '@apollo/client/link/error' 3 | import { logErrorMessages } from '@vue/apollo-util' 4 | import { isServer } from './env.js' 5 | 6 | export function createApollo() { 7 | const cache = new InMemoryCache() 8 | 9 | const restoreCache = !isServer && !!window._INITIAL_STATE_?.apollo 10 | if (restoreCache) { 11 | cache.restore(window._INITIAL_STATE_.apollo) 12 | } 13 | 14 | // HTTP connection to the API 15 | const httpLink = createHttpLink({ 16 | // You should use an absolute URL here 17 | uri: 'http://localhost:4042/graphql', 18 | }) 19 | 20 | // Handle errors 21 | const errorLink = onError((error) => { 22 | logErrorMessages(error) 23 | }) 24 | 25 | const apolloClient = new ApolloClient({ 26 | cache, 27 | link: errorLink.concat(httpLink), 28 | ssrForceFetchDelay: restoreCache ? 100 : undefined, 29 | ssrMode: isServer, 30 | }) 31 | 32 | return { 33 | apolloClient, 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /packages/test-e2e-ssr/src/app.ts: -------------------------------------------------------------------------------- 1 | import { DefaultApolloClient } from '@vue/apollo-composable' 2 | import { createApp } from 'vue' 3 | import { createApollo } from './apollo' 4 | import App from './components/App.vue' 5 | import { createMyRouter } from './router' 6 | import '@/assets/styles/tailwind.css' 7 | 8 | export function createMyApp() { 9 | const app = createApp(App) 10 | 11 | const { apolloClient } = createApollo() 12 | app.provide(DefaultApolloClient, apolloClient) 13 | 14 | const { router } = createMyRouter() 15 | app.use(router) 16 | 17 | return { 18 | app, 19 | router, 20 | apolloClient, 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /packages/test-e2e-ssr/src/assets/styles/tailwind.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | 3 | @tailwind components; 4 | 5 | @tailwind utilities; 6 | -------------------------------------------------------------------------------- /packages/test-e2e-ssr/src/components/App.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 23 | -------------------------------------------------------------------------------- /packages/test-e2e-ssr/src/components/ClientOnly.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 14 | -------------------------------------------------------------------------------- /packages/test-e2e-ssr/src/components/GlobalLoading.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 17 | -------------------------------------------------------------------------------- /packages/test-e2e-ssr/src/components/LazyQueryImmediately.vue: -------------------------------------------------------------------------------- 1 | 35 | 36 | 59 | -------------------------------------------------------------------------------- /packages/test-e2e-ssr/src/components/MessageItem.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 21 | -------------------------------------------------------------------------------- /packages/test-e2e-ssr/src/components/Welcome.vue: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /packages/test-e2e-ssr/src/context.ts: -------------------------------------------------------------------------------- 1 | export interface Context { 2 | state: { 3 | apollo?: any 4 | } 5 | } 6 | 7 | declare global { 8 | interface Window { 9 | _INITIAL_STATE_: Context['state'] 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /packages/test-e2e-ssr/src/entry-client.ts: -------------------------------------------------------------------------------- 1 | import { createMyApp } from './app.js' 2 | 3 | const { app, router } = createMyApp() 4 | 5 | router.isReady().then(() => { 6 | app.mount('#app') 7 | }) 8 | -------------------------------------------------------------------------------- /packages/test-e2e-ssr/src/entry-server.ts: -------------------------------------------------------------------------------- 1 | import type { Context } from '@apollo/client' 2 | import { renderToString } from 'vue/server-renderer' 3 | import { createMyApp } from './app.js' 4 | import 'isomorphic-fetch' 5 | 6 | export async function render(url: string) { 7 | const { 8 | app, 9 | router, 10 | apolloClient, 11 | } = await createMyApp() 12 | 13 | await router.push(url) 14 | await router.isReady() 15 | 16 | const context: Context = { 17 | state: {}, 18 | } 19 | 20 | const html = await renderToString(app, context) 21 | 22 | context.state.apollo = apolloClient.extract() 23 | 24 | return { 25 | html, 26 | context, 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /packages/test-e2e-ssr/src/env.ts: -------------------------------------------------------------------------------- 1 | export const isServer = typeof window === 'undefined' 2 | -------------------------------------------------------------------------------- /packages/test-e2e-ssr/src/router.ts: -------------------------------------------------------------------------------- 1 | import { createMemoryHistory, createRouter, createWebHistory } from 'vue-router' 2 | import { isServer } from './env.js' 3 | 4 | export function createMyRouter() { 5 | const router = createRouter({ 6 | history: isServer ? createMemoryHistory() : createWebHistory(), 7 | routes: [ 8 | { 9 | path: '/', 10 | name: 'home', 11 | component: () => import('./components/Welcome.vue'), 12 | }, 13 | { 14 | path: '/channel/:id', 15 | name: 'channel', 16 | component: () => import('./components/ChannelView.vue'), 17 | props: true, 18 | }, 19 | { 20 | path: '/lazy-query', 21 | component: () => import('./components/LazyQuery.vue'), 22 | }, 23 | { 24 | path: '/lazy-query-immediately', 25 | component: () => import('./components/LazyQueryImmediately.vue'), 26 | }, 27 | ], 28 | }) 29 | 30 | return { 31 | router, 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /packages/test-e2e-ssr/src/shims-vue.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.vue' { 2 | import type { DefineComponent } from 'vue' 3 | 4 | const component: DefineComponent 5 | export default component 6 | } 7 | -------------------------------------------------------------------------------- /packages/test-e2e-ssr/tailwind.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('tailwindcss').Config} */ 2 | module.exports = { 3 | content: ['./index.html', './src/**/*.{vue,js,ts,jsx,tsx}'], 4 | theme: { 5 | extend: {}, 6 | }, 7 | plugins: [], 8 | } 9 | -------------------------------------------------------------------------------- /packages/test-e2e-ssr/tests/e2e/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: [ 3 | 'cypress', 4 | ], 5 | env: { 6 | 'mocha': true, 7 | 'cypress/globals': true, 8 | }, 9 | rules: { 10 | strict: 'off', 11 | }, 12 | } 13 | -------------------------------------------------------------------------------- /packages/test-e2e-ssr/tests/e2e/support/commands.ts: -------------------------------------------------------------------------------- 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 is will overwrite an existing command -- 25 | // Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... }) 26 | -------------------------------------------------------------------------------- /packages/test-e2e-ssr/tests/e2e/support/index.ts: -------------------------------------------------------------------------------- 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/test-e2e-ssr/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "esnext", 4 | "jsx": "preserve", 5 | "lib": [ 6 | "esnext", 7 | "dom", 8 | "dom.iterable", 9 | "scripthost" 10 | ], 11 | "baseUrl": ".", 12 | "module": "esnext", 13 | "moduleResolution": "node", 14 | "paths": { 15 | "@/*": [ 16 | "src/*" 17 | ] 18 | }, 19 | "types": [ 20 | "vite/client", 21 | "cypress", 22 | "node" 23 | ], 24 | "strict": true, 25 | "importHelpers": true, 26 | "sourceMap": true, 27 | "allowSyntheticDefaultImports": true, 28 | "esModuleInterop": true, 29 | "skipLibCheck": true 30 | }, 31 | "include": [ 32 | "src/**/*.ts", 33 | "src/**/*.tsx", 34 | "src/**/*.vue", 35 | "tests/**/*.ts", 36 | "tests/**/*.tsx" 37 | ], 38 | "exclude": [ 39 | "node_modules" 40 | ] 41 | } 42 | -------------------------------------------------------------------------------- /packages/test-e2e-ssr/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { resolve } from 'node:path' 2 | import vue from '@vitejs/plugin-vue' 3 | import { defineConfig } from 'vite' 4 | 5 | // https://vitejs.dev/config/ 6 | export default defineConfig({ 7 | plugins: [vue()], 8 | resolve: { 9 | alias: { 10 | '@': resolve(__dirname, './src'), 11 | }, 12 | }, 13 | }) 14 | -------------------------------------------------------------------------------- /packages/test-e2e/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | 5 | /tests/e2e/videos/ 6 | /tests/e2e/screenshots/ 7 | 8 | # local env files 9 | .env.local 10 | .env.*.local 11 | 12 | # Log files 13 | npm-debug.log* 14 | yarn-debug.log* 15 | yarn-error.log* 16 | 17 | # Editor directories and files 18 | .idea 19 | .vscode 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw* 25 | 26 | /live/ 27 | -------------------------------------------------------------------------------- /packages/test-e2e/.graphqlconfig.yml: -------------------------------------------------------------------------------- 1 | projects: 2 | app: 3 | schemaPath: apollo-server/schema.graphql 4 | includes: 5 | - '**/*.gql' 6 | extensions: 7 | endpoints: 8 | default: 'http://localhost:4000/graphql' 9 | -------------------------------------------------------------------------------- /packages/test-e2e/.postcssrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | autoprefixer: {}, 4 | }, 5 | } 6 | -------------------------------------------------------------------------------- /packages/test-e2e/README.md: -------------------------------------------------------------------------------- 1 | # ApolloChat 2 | 3 | Demo app: Vue + Apollo + Graphql + vue-cli 3 4 | 5 | ### Setup project 6 | 7 | ``` 8 | pnpm i 9 | ``` 10 | 11 | ### Development 12 | 13 | ``` 14 | pnpm run apollo:run 15 | pnpm run serve 16 | ``` 17 | -------------------------------------------------------------------------------- /packages/test-e2e/apollo-server/connectors/channels.js: -------------------------------------------------------------------------------- 1 | const channels = [ 2 | { id: 'general', name: 'General discussion' }, 3 | { id: 'random', name: 'Have fun chatting!' }, 4 | { id: 'help', name: 'Ask for or give help' }, 5 | ] 6 | 7 | exports.getAll = (context) => { 8 | return channels 9 | } 10 | 11 | exports.getOne = (id, context) => { 12 | return channels.find(c => c.id === id) 13 | } 14 | -------------------------------------------------------------------------------- /packages/test-e2e/apollo-server/context.js: -------------------------------------------------------------------------------- 1 | const users = require('./connectors/users') 2 | 3 | // Context passed to all resolvers (third argument) 4 | // req => Query 5 | // connection => Subscription 6 | 7 | module.exports = ({ req, connection }) => { 8 | // If the websocket context was already resolved 9 | if (connection && connection.context) 10 | return connection.context 11 | 12 | let rawToken 13 | // HTTP 14 | if (req) 15 | rawToken = req.get('Authorization') 16 | // Websocket 17 | if (connection) 18 | rawToken = connection.Authorization 19 | 20 | // Token 21 | const token = rawToken ? JSON.parse(rawToken) : null 22 | let userId 23 | 24 | // User validation 25 | if (token && users.validateToken(token)) { 26 | userId = token.userId 27 | } 28 | 29 | // return new Promise(resolve => { 30 | // setTimeout(() => { 31 | // resolve({ 32 | // token, 33 | // userId, 34 | // }) 35 | // }, 3000) 36 | // }) 37 | return { 38 | token, 39 | userId, 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /packages/test-e2e/apollo-server/directives.js: -------------------------------------------------------------------------------- 1 | const PrivateDirective = require('./directives/private') 2 | 3 | module.exports = { 4 | private: PrivateDirective, 5 | } 6 | -------------------------------------------------------------------------------- /packages/test-e2e/apollo-server/directives/private.js: -------------------------------------------------------------------------------- 1 | const { ApolloError } = require('apollo-server-express') 2 | const { defaultFieldResolver } = require('graphql') 3 | const { SchemaDirectiveVisitor } = require('graphql-tools') 4 | 5 | module.exports = class PrivateDirective extends SchemaDirectiveVisitor { 6 | visitFieldDefinition(field) { 7 | const { resolve = defaultFieldResolver } = field 8 | field.resolve = (root, args, context, info) => { 9 | if (!context.userId) 10 | throw new ApolloError('Unauthorized', 'unauthorized') 11 | return resolve(root, args, context, info) 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /packages/test-e2e/apollo-server/reset.js: -------------------------------------------------------------------------------- 1 | exports.reset = () => { 2 | require('./connectors/messages.js').reset() 3 | require('./connectors/users.js').reset() 4 | } 5 | -------------------------------------------------------------------------------- /packages/test-e2e/apollo-server/triggers.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | MESSAGE_CHANGED: 'message_changed', 3 | } 4 | -------------------------------------------------------------------------------- /packages/test-e2e/apollo-server/type-defs.js: -------------------------------------------------------------------------------- 1 | const fs = require('node:fs') 2 | const path = require('node:path') 3 | 4 | module.exports = fs.readFileSync(path.resolve(__dirname, './schema.graphql'), { encoding: 'utf8' }) 5 | -------------------------------------------------------------------------------- /packages/test-e2e/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | '@vue/cli-plugin-babel/preset', 4 | ], 5 | } 6 | -------------------------------------------------------------------------------- /packages/test-e2e/cypress.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'cypress' 2 | 3 | export default defineConfig({ 4 | fixturesFolder: 'tests/e2e/fixtures', 5 | screenshotsFolder: 'tests/e2e/screenshots', 6 | videosFolder: 'tests/e2e/videos', 7 | e2e: { 8 | specPattern: 'tests/e2e/specs/**/*.cy.{js,jsx,ts,tsx}', 9 | supportFile: 'tests/e2e/support/index.js', 10 | }, 11 | }) 12 | -------------------------------------------------------------------------------- /packages/test-e2e/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuejs/apollo/fb027e6adf4d4129fb26f8c918060771a0afd59b/packages/test-e2e/public/favicon.ico -------------------------------------------------------------------------------- /packages/test-e2e/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 11 | Apollo Chat 12 | 13 | 14 | 17 |
18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /packages/test-e2e/src/components/ManualAddSmartQuery.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 47 | -------------------------------------------------------------------------------- /packages/test-e2e/src/components/MessageItem.vue: -------------------------------------------------------------------------------- 1 | 27 | 28 | 39 | 40 | 64 | -------------------------------------------------------------------------------- /packages/test-e2e/src/components/MockSendMessage.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 28 | 29 | 36 | -------------------------------------------------------------------------------- /packages/test-e2e/src/components/PartialError.vue: -------------------------------------------------------------------------------- 1 | 38 | 39 | 57 | 58 | 62 | -------------------------------------------------------------------------------- /packages/test-e2e/src/components/WelcomeView.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 17 | 18 | 36 | -------------------------------------------------------------------------------- /packages/test-e2e/src/graphql/channel.gql: -------------------------------------------------------------------------------- 1 | #import "./channelFragment.gql" 2 | #import "./messageFragment.gql" 3 | 4 | query channel ($id: ID!) { 5 | channel (id: $id) { 6 | ...channel 7 | messages { 8 | ...message 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /packages/test-e2e/src/graphql/channelFragment.gql: -------------------------------------------------------------------------------- 1 | fragment channel on Channel { 2 | id 3 | name 4 | } 5 | -------------------------------------------------------------------------------- /packages/test-e2e/src/graphql/channels.gql: -------------------------------------------------------------------------------- 1 | #import "./channelFragment.gql" 2 | 3 | query channels { 4 | channels { 5 | ...channel 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /packages/test-e2e/src/graphql/messageAdd.gql: -------------------------------------------------------------------------------- 1 | #import "./messageFragment.gql" 2 | 3 | mutation messageAdd ($input: MessageAdd!) { 4 | messageAdd (input: $input) { 5 | ...message 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /packages/test-e2e/src/graphql/messageChanged.gql: -------------------------------------------------------------------------------- 1 | #import "./messageFragment.gql" 2 | 3 | subscription messageChanged ($channelId: ID!) { 4 | messageChanged (channelId: $channelId) { 5 | type 6 | message { 7 | ...message 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /packages/test-e2e/src/graphql/messageFragment.gql: -------------------------------------------------------------------------------- 1 | #import "./userFragment.gql" 2 | 3 | fragment message on Message { 4 | id 5 | content 6 | user { 7 | ...user 8 | } 9 | dateAdded 10 | dateUpdated 11 | } 12 | -------------------------------------------------------------------------------- /packages/test-e2e/src/graphql/messageRemove.gql: -------------------------------------------------------------------------------- 1 | #import "./messageFragment.gql" 2 | 3 | mutation messageRemove ($id: ID!) { 4 | messageRemove (id: $id) { 5 | ...message 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /packages/test-e2e/src/graphql/messageUpdate.gql: -------------------------------------------------------------------------------- 1 | #import "./messageFragment.gql" 2 | 3 | mutation messageUpdate ($input: MessageUpdate!) { 4 | messageUpdate (input: $input) { 5 | ...message 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /packages/test-e2e/src/graphql/userCurrent.gql: -------------------------------------------------------------------------------- 1 | #import "./userFragment.gql" 2 | 3 | query userCurrent { 4 | userCurrent { 5 | ...user 6 | email 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /packages/test-e2e/src/graphql/userFragment.gql: -------------------------------------------------------------------------------- 1 | fragment user on User { 2 | id 3 | nickname 4 | } 5 | -------------------------------------------------------------------------------- /packages/test-e2e/src/graphql/userLogin.gql: -------------------------------------------------------------------------------- 1 | #import "./userFragment.gql" 2 | 3 | mutation userLogin ($email: String!, $password: String!) { 4 | userLogin (email: $email, password: $password) { 5 | user { 6 | ...user 7 | email 8 | } 9 | token { 10 | id 11 | userId 12 | expiration 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /packages/test-e2e/src/graphql/userLogout.gql: -------------------------------------------------------------------------------- 1 | mutation userLogout { 2 | userLogout 3 | } 4 | -------------------------------------------------------------------------------- /packages/test-e2e/src/graphql/userRegister.gql: -------------------------------------------------------------------------------- 1 | mutation userRegister ($input: UserRegister!) { 2 | userRegister(input: $input) 3 | } 4 | -------------------------------------------------------------------------------- /packages/test-e2e/src/main.js: -------------------------------------------------------------------------------- 1 | import VueApolloComponents from '@vue/apollo-components' 2 | import { createApp } from 'vue' 3 | import App from './App.vue' 4 | import router from './router' 5 | import store from './store' 6 | import { apolloProvider } from './vue-apollo' 7 | 8 | const app = createApp(App) 9 | app.use(router) 10 | app.use(store) 11 | app.use(apolloProvider) 12 | app.use(VueApolloComponents) 13 | app.mount('#app') 14 | -------------------------------------------------------------------------------- /packages/test-e2e/src/mixins/UserCurrent.js: -------------------------------------------------------------------------------- 1 | import USER_CURRENT from '../graphql/userCurrent.gql' 2 | 3 | // @vue/component 4 | export default { 5 | apollo: { 6 | userCurrent: USER_CURRENT, 7 | }, 8 | } 9 | -------------------------------------------------------------------------------- /packages/test-e2e/src/router.js: -------------------------------------------------------------------------------- 1 | import { createRouter, createWebHistory } from 'vue-router' 2 | import ChannelView from './components/ChannelView.vue' 3 | import ManualAddSmartQuery from './components/ManualAddSmartQuery.vue' 4 | import PartialError from './components/PartialError.vue' 5 | import UserLogin from './components/UserLogin.vue' 6 | import WelcomeView from './components/WelcomeView.vue' 7 | 8 | export default createRouter({ 9 | history: createWebHistory(), 10 | routes: [ 11 | { 12 | path: '/', 13 | name: 'home', 14 | component: WelcomeView, 15 | meta: { 16 | private: true, 17 | }, 18 | }, 19 | { 20 | path: '/login', 21 | name: 'login', 22 | component: UserLogin, 23 | }, 24 | { 25 | path: '/chan/:id', 26 | name: 'channel', 27 | component: ChannelView, 28 | props: true, 29 | meta: { 30 | private: true, 31 | }, 32 | }, 33 | { 34 | path: '/partial-error', 35 | component: PartialError, 36 | }, 37 | { 38 | path: '/manual-add-smart-query', 39 | component: ManualAddSmartQuery, 40 | }, 41 | { 42 | path: '/update-cache', 43 | component: () => import('./components/UpdateCache.vue'), 44 | }, 45 | ], 46 | }) 47 | -------------------------------------------------------------------------------- /packages/test-e2e/src/store.js: -------------------------------------------------------------------------------- 1 | import { createStore } from 'vuex' 2 | 3 | export default createStore({ 4 | state: { 5 | 6 | }, 7 | mutations: { 8 | 9 | }, 10 | actions: { 11 | 12 | }, 13 | }) 14 | -------------------------------------------------------------------------------- /packages/test-e2e/src/style/imports.styl: -------------------------------------------------------------------------------- 1 | $color = #41b883 2 | $border = rgba(black, .08) 1px solid 3 | -------------------------------------------------------------------------------- /packages/test-e2e/tests/e2e/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": [ 3 | "cypress" 4 | ], 5 | "env": { 6 | "mocha": true, 7 | "cypress/globals": true 8 | }, 9 | "rules": { 10 | "strict": "off" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /packages/test-e2e/tests/e2e/specs/cache.cy.js: -------------------------------------------------------------------------------- 1 | describe('cache', () => { 2 | it('add an item to the list', () => { 3 | cy.visit('/update-cache') 4 | 5 | cy.get('.item-list ul li').should('have.length', 1) 6 | cy.get('.update-count').should('contain', 'Changes: 1') 7 | cy.get('button.add').click() 8 | cy.get('.item-list ul li').should('have.length', 2) 9 | cy.get('.item-list ul li').should('contain', 'Item 2') 10 | cy.get('.update-count').should('contain', 'Changes: 2') 11 | }) 12 | }) 13 | -------------------------------------------------------------------------------- /packages/test-e2e/tests/e2e/specs/errorPolicy.cy.js: -------------------------------------------------------------------------------- 1 | describe('errorPolicy', () => { 2 | it('supports `errorPolicy` option', () => { 3 | cy.visit('/partial-error') 4 | 5 | // All 6 | cy.get('.all .result').should('contain', '"good":"good"').should('contain', '"bad":null') 7 | cy.get('.all .error').should('contain', 'Error: GraphQL error: An error') 8 | 9 | // None 10 | cy.get('.none .result').should('not.contain', 'good').should('not.contain', 'bad') 11 | cy.get('.none .error').should('contain', 'Error: An error') 12 | 13 | // Ignore 14 | cy.get('.ignore .result').should('contain', '"good":"good"').should('contain', '"bad":null') 15 | cy.get('.ignore .error').should('not.exist') 16 | }) 17 | }) 18 | -------------------------------------------------------------------------------- /packages/test-e2e/tests/e2e/specs/manual-smart-query.cy.js: -------------------------------------------------------------------------------- 1 | describe('Manual Smart Query', () => { 2 | it('should support loading key', () => { 3 | cy.visit('/manual-add-smart-query') 4 | cy.contains('Loading...') 5 | cy.contains('42') 6 | cy.contains('[{"isLoading":true,"countModifier":1},{"isLoading":false,"countModifier":-1}]') 7 | }) 8 | }) 9 | -------------------------------------------------------------------------------- /packages/test-e2e/tests/e2e/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 is will overwrite an existing command -- 25 | // Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... }) 26 | -------------------------------------------------------------------------------- /packages/test-e2e/tests/e2e/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/test-e2e/vue.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('@vue/cli-service').ProjectOptions} */ 2 | module.exports = { 3 | // pluginOptions: { 4 | // apollo: { 5 | // enableMocks: false, 6 | // enableEngine: false, 7 | // }, 8 | // }, 9 | 10 | productionSourceMap: false, 11 | 12 | /* Without vue-cli-plugin-apollo 0.20.0+ */ 13 | // chainWebpack: config => { 14 | // config.module 15 | // .rule('vue') 16 | // .use('vue-loader') 17 | // .loader('vue-loader') 18 | // .tap(options => { 19 | // options.transpileOptions = { 20 | // transforms: { 21 | // dangerousTaggedTemplateString: true, 22 | // }, 23 | // } 24 | // return options 25 | // }) 26 | // } 27 | 28 | chainWebpack: (config) => { 29 | config.module.rule('graphql') 30 | .test(/\.gql$/) 31 | .use('graphql-tag/loader') 32 | .loader('graphql-tag/loader') 33 | .end() 34 | }, 35 | } 36 | -------------------------------------------------------------------------------- /packages/test-server/bin.mjs: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 'use strict' 3 | 4 | import './dist/index.js' 5 | -------------------------------------------------------------------------------- /packages/test-server/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "test-server", 3 | "type": "module", 4 | "version": "4.0.0-alpha.16", 5 | "private": true, 6 | "bin": { 7 | "test-server": "./bin.mjs" 8 | }, 9 | "scripts": { 10 | "build": "tsc -d", 11 | "prepare": "pnpm run build" 12 | }, 13 | "dependencies": { 14 | "@apollo/server": "^4.7.3", 15 | "@graphql-tools/schema": "^10.0.0", 16 | "body-parser": "^1.20.2", 17 | "cors": "^2.8.5", 18 | "express": "^4.18.1", 19 | "graphql": "^16.6.0", 20 | "graphql-subscriptions": "^2.0.0", 21 | "graphql-tag": "^2.12.6", 22 | "graphql-ws": "^5.13.1", 23 | "shortid": "^2.2.16", 24 | "ws": "^8.13.0" 25 | }, 26 | "devDependencies": { 27 | "@types/body-parser": "^1.19.2", 28 | "@types/cors": "^2.8.13", 29 | "@types/express": "^4.17.17", 30 | "@types/shortid": "^0.0.29", 31 | "@types/ws": "^8.5.5", 32 | "typescript": "^4.7.4" 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /packages/test-server/src/data.ts: -------------------------------------------------------------------------------- 1 | export interface Channel { 2 | id: string 3 | label: string 4 | messages: Message[] 5 | } 6 | 7 | export interface Message { 8 | id: string 9 | channel: Channel 10 | text: string 11 | } 12 | 13 | export let channels: Channel[] = [] 14 | 15 | export function resetDatabase(): void { 16 | channels = [ 17 | { 18 | id: 'general', 19 | label: 'General', 20 | messages: [], 21 | }, 22 | { 23 | id: 'random', 24 | label: 'Random', 25 | messages: [], 26 | }, 27 | ] 28 | } 29 | 30 | export function seedDatabase(): void { 31 | channels[0].messages = [ 32 | { 33 | id: '1', 34 | channel: channels[0], 35 | text: 'Meow?', 36 | }, 37 | { 38 | id: '2', 39 | channel: channels[0], 40 | text: 'Meow!', 41 | }, 42 | ] 43 | channels[1].messages = [ 44 | { 45 | id: '3', 46 | channel: channels[1], 47 | text: 'Hello world!', 48 | }, 49 | ] 50 | } 51 | 52 | resetDatabase() 53 | -------------------------------------------------------------------------------- /packages/test-server/src/util.ts: -------------------------------------------------------------------------------- 1 | import type { GraphQLErrorExtensions } from 'graphql' 2 | import { GraphQLError } from 'graphql' 3 | 4 | const shouldSimulateLatency = process.argv.includes('--simulate-latency') 5 | 6 | let latency = 500 7 | if (shouldSimulateLatency) { 8 | const index = process.argv.indexOf('--simulate-latency') 9 | if (index !== -1 && process.argv.length > index + 1) { 10 | latency = Number.parseInt(process.argv[index + 1]) 11 | } 12 | } 13 | 14 | export function simulateLatency() { 15 | return new Promise((resolve) => { 16 | if (shouldSimulateLatency) { 17 | setTimeout(resolve, latency) 18 | } 19 | else { 20 | resolve() 21 | } 22 | }) 23 | } 24 | 25 | export class GraphQLErrorWithCode extends GraphQLError { 26 | constructor(message: string, code: string, extensions?: GraphQLErrorExtensions) { 27 | super(message, null, null, null, null, null, { 28 | extensions: { 29 | code, 30 | ...extensions, 31 | }, 32 | }) 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /packages/test-server/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "esnext", 4 | "lib": [ 5 | "esnext" 6 | ], 7 | "module": "esnext", 8 | "moduleResolution": "node", 9 | "strict": true, 10 | "importHelpers": true, 11 | "outDir": "dist", 12 | "sourceMap": true, 13 | "allowSyntheticDefaultImports": true, 14 | "esModuleInterop": true, 15 | "skipLibCheck": true 16 | }, 17 | "include": [ 18 | "src/**/*.ts" 19 | ], 20 | "exclude": [ 21 | "node_modules" 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /packages/vue-apollo-components/.npmignore: -------------------------------------------------------------------------------- 1 | src/ 2 | types/test/ 3 | tests/ 4 | .babelrc 5 | .eslintrc.js 6 | -------------------------------------------------------------------------------- /packages/vue-apollo-components/README.md: -------------------------------------------------------------------------------- 1 | # Apollo and GraphQL for Vue.js (Components with Slots) 2 | 3 | [![npm](https://img.shields.io/npm/v/@vue/apollo-components.svg) ![npm](https://img.shields.io/npm/dm/@vue/apollo-components.svg)](https://www.npmjs.com/package/@vue/apollo-components) 4 | [![apollo3](https://img.shields.io/badge/apollo-3.x-blue.svg)](https://www.apollographql.com/) 5 | [![vue3](https://img.shields.io/badge/vue-3-brightgreen.svg)](https://vuejs.org/) 6 | [![CircleCI branch](https://img.shields.io/circleci/build/github/vuejs/vue-apollo/v4.svg)](https://circleci.com/gh/vuejs/vue-apollo/tree/v4) 7 | 8 |

9 | 10 |

11 | 12 | :book: Documentation [**for Vue 3**](http://v4.apollo.vuejs.org) | [for Vue 2](https://apollo.vuejs.org/) 13 | 14 | [:pen: Contributing guide](./CONTRIBUTING.md) 15 | 16 | [:heart: Sponsor me!](https://github.com/sponsors/Akryum) 17 | 18 | ```bash 19 | npm i @vue/apollo-components 20 | pnpm i @vue/apollo-components 21 | yarn add @vue/apollo-components 22 | ``` 23 | 24 | ## Sponsors 25 | 26 |

27 | 28 | 29 | 30 |

31 | -------------------------------------------------------------------------------- /packages/vue-apollo-components/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | [require('@babel/preset-env'), { modules: false }], 4 | ], 5 | plugins: [ 6 | require('@babel/plugin-proposal-class-properties'), 7 | [require('@babel/plugin-transform-for-of'), { assumeArray: true }], 8 | ], 9 | } 10 | -------------------------------------------------------------------------------- /packages/vue-apollo-components/build/rollup.config.base.js: -------------------------------------------------------------------------------- 1 | import babel from 'rollup-plugin-babel' 2 | import cjs from 'rollup-plugin-commonjs' 3 | import resolve from 'rollup-plugin-node-resolve' 4 | import replace from 'rollup-plugin-replace' 5 | 6 | const config = require('../package.json') 7 | 8 | export default { 9 | input: 'src/index.js', 10 | plugins: [ 11 | resolve({ 12 | jsnext: true, 13 | main: true, 14 | browser: true, 15 | }), 16 | cjs({ 17 | exclude: 'src/**', 18 | }), 19 | babel({ 20 | exclude: 'node_modules/**', 21 | }), 22 | replace({ 23 | VERSION: JSON.stringify(config.version), 24 | }), 25 | ], 26 | external: ['@apollo/client', 'graphql-tag', 'vue'], 27 | } 28 | -------------------------------------------------------------------------------- /packages/vue-apollo-components/build/rollup.config.browser.js: -------------------------------------------------------------------------------- 1 | import { uglify } from 'rollup-plugin-uglify' 2 | import { minify } from 'uglify-es' 3 | import base from './rollup.config.base' 4 | 5 | const config = Object.assign({}, base, { 6 | output: { 7 | file: 'dist/vue-apollo-components.min.js', 8 | format: 'iife', 9 | name: 'VueApolloComponents', 10 | }, 11 | }) 12 | 13 | config.plugins.push(uglify({}, minify)) 14 | 15 | export default config 16 | -------------------------------------------------------------------------------- /packages/vue-apollo-components/build/rollup.config.es.js: -------------------------------------------------------------------------------- 1 | import base from './rollup.config.base' 2 | 3 | const config = Object.assign({}, base, { 4 | output: { 5 | file: 'dist/vue-apollo-components.esm.mjs', 6 | format: 'es', 7 | name: 'vue-apollo-components', 8 | }, 9 | }) 10 | 11 | export default config 12 | -------------------------------------------------------------------------------- /packages/vue-apollo-components/build/rollup.config.umd.js: -------------------------------------------------------------------------------- 1 | import base from './rollup.config.base' 2 | 3 | const config = Object.assign({}, base, { 4 | output: { 5 | file: 'dist/vue-apollo-components.umd.js', 6 | format: 'umd', 7 | name: 'vue-apollo-components', 8 | }, 9 | }) 10 | 11 | export default config 12 | -------------------------------------------------------------------------------- /packages/vue-apollo-components/src/index.js: -------------------------------------------------------------------------------- 1 | import CApolloMutation from './ApolloMutation' 2 | import CApolloQuery from './ApolloQuery' 3 | import CApolloSubscribeToMore from './ApolloSubscribeToMore' 4 | 5 | const plugin = {} 6 | 7 | export function install(app, options) { 8 | app.component('ApolloQuery', CApolloQuery) 9 | app.component('ApolloSubscribeToMore', CApolloSubscribeToMore) 10 | app.component('ApolloMutation', CApolloMutation) 11 | } 12 | 13 | plugin.install = install 14 | 15 | // eslint-disable-next-line no-undef 16 | plugin.version = VERSION 17 | 18 | // Apollo provider 19 | export const ApolloProvider = plugin 20 | 21 | // Components 22 | export const ApolloQuery = CApolloQuery 23 | export const ApolloSubscribeToMore = CApolloSubscribeToMore 24 | export const ApolloMutation = CApolloMutation 25 | 26 | // Auto-install 27 | let GlobalVue = null 28 | if (typeof window !== 'undefined') { 29 | GlobalVue = window.Vue 30 | } 31 | else if (typeof globalThis !== 'undefined') { 32 | GlobalVue = globalThis.Vue 33 | } 34 | if (GlobalVue) { 35 | GlobalVue.use(plugin) 36 | } 37 | 38 | export default plugin 39 | -------------------------------------------------------------------------------- /packages/vue-apollo-composable/README.md: -------------------------------------------------------------------------------- 1 | # Apollo and GraphQL for Vue.js (Composition API) 2 | 3 | [![npm](https://img.shields.io/npm/v/@vue/apollo-composable.svg) ![npm](https://img.shields.io/npm/dm/@vue/apollo-composable.svg)](https://www.npmjs.com/package/@vue/apollo-composable) 4 | [![apollo3](https://img.shields.io/badge/apollo-3.x-blue.svg)](https://www.apollographql.com/) 5 | [![vue3](https://img.shields.io/badge/vue-3-brightgreen.svg)](https://vuejs.org/) 6 | [![CircleCI branch](https://img.shields.io/circleci/build/github/vuejs/vue-apollo/v4.svg)](https://circleci.com/gh/vuejs/vue-apollo/tree/v4) 7 | 8 |

9 | 10 |

11 | 12 | :book: Documentation [**for Vue 3**](http://v4.apollo.vuejs.org) | [for Vue 2](https://apollo.vuejs.org/) 13 | 14 | [:pen: Contributing guide](./CONTRIBUTING.md) 15 | 16 | [:heart: Sponsor me!](https://github.com/sponsors/Akryum) 17 | 18 | ```bash 19 | npm i @vue/apollo-composable 20 | pnpm i @vue/apollo-composable 21 | yarn add @vue/apollo-composable 22 | ``` 23 | 24 | ## Sponsors 25 | 26 |

27 | 28 | 29 | 30 |

31 | -------------------------------------------------------------------------------- /packages/vue-apollo-composable/esbuild.mjs: -------------------------------------------------------------------------------- 1 | import path from 'node:path' 2 | import esbuild from 'esbuild' 3 | import { nodeExternalsPlugin } from 'esbuild-node-externals' 4 | 5 | /** @typedef {import('esbuild').BuildOptions} BuildOptions */ 6 | 7 | /** 8 | * @typedef Build 9 | * @prop {BuildOptions['format']} format 10 | * @prop {string} file 11 | */ 12 | 13 | (async () => { 14 | /** @type {Build[]} */ 15 | const builds = [ 16 | { format: 'esm', file: 'index.mjs' }, 17 | { format: 'cjs', file: 'index.js' }, 18 | ] 19 | for (const { format, file } of builds) { 20 | await esbuild.build({ 21 | entryPoints: ['./src/index.ts'], 22 | bundle: true, 23 | platform: 'neutral', 24 | format, 25 | outfile: path.join('dist', file), 26 | sourcemap: true, 27 | target: 'es2018', 28 | plugins: [ 29 | nodeExternalsPlugin(), 30 | ], 31 | }) 32 | } 33 | })() 34 | -------------------------------------------------------------------------------- /packages/vue-apollo-composable/src/index.ts: -------------------------------------------------------------------------------- 1 | export { 2 | ApolloClients, 3 | DefaultApolloClient, 4 | provideApolloClient, 5 | provideApolloClients, 6 | useApolloClient, 7 | UseApolloClientReturn, 8 | } from './useApolloClient' 9 | 10 | export { 11 | useLazyQuery, 12 | } from './useLazyQuery' 13 | 14 | export { 15 | useGlobalMutationLoading, 16 | useGlobalQueryLoading, 17 | useGlobalSubscriptionLoading, 18 | useMutationLoading, 19 | useQueryLoading, 20 | useSubscriptionLoading, 21 | } from './useLoading' 22 | 23 | export { 24 | MutateFunction, 25 | MutateOverrideOptions, 26 | MutateResult, 27 | useMutation, 28 | UseMutationOptions, 29 | UseMutationReturn, 30 | } from './useMutation' 31 | 32 | export { 33 | useQuery, 34 | UseQueryOptions, 35 | UseQueryReturn, 36 | } from './useQuery' 37 | 38 | export { 39 | useResult, 40 | UseResultReturn, 41 | } from './useResult' 42 | 43 | export { 44 | useSubscription, 45 | UseSubscriptionOptions, 46 | UseSubscriptionReturn, 47 | } from './useSubscription' 48 | -------------------------------------------------------------------------------- /packages/vue-apollo-composable/src/useLoading.ts: -------------------------------------------------------------------------------- 1 | import { computed } from 'vue-demi' 2 | import { getCurrentTracking, globalTracking } from './util/loadingTracking' 3 | 4 | export function useQueryLoading() { 5 | const { tracking } = getCurrentTracking() 6 | if (!tracking) 7 | throw new Error('useQueryLoading must be called inside a setup function.') 8 | return computed(() => tracking.queries.value > 0) 9 | } 10 | 11 | export function useMutationLoading() { 12 | const { tracking } = getCurrentTracking() 13 | if (!tracking) 14 | throw new Error('useMutationLoading must be called inside a setup function.') 15 | return computed(() => tracking.mutations.value > 0) 16 | } 17 | 18 | export function useSubscriptionLoading() { 19 | const { tracking } = getCurrentTracking() 20 | if (!tracking) 21 | throw new Error('useSubscriptionLoading must be called inside a setup function.') 22 | return computed(() => tracking.subscriptions.value > 0) 23 | } 24 | 25 | export function useGlobalQueryLoading() { 26 | return computed(() => globalTracking.queries.value > 0) 27 | } 28 | 29 | export function useGlobalMutationLoading() { 30 | return computed(() => globalTracking.mutations.value > 0) 31 | } 32 | 33 | export function useGlobalSubscriptionLoading() { 34 | return computed(() => globalTracking.subscriptions.value > 0) 35 | } 36 | -------------------------------------------------------------------------------- /packages/vue-apollo-composable/src/util/ExtractSingleKey.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Check if a type is a union, and return true if so, otherwise false. 3 | */ 4 | export type IsUnion = U extends any ? ([T] extends [U] ? false : true) : never 5 | 6 | /** 7 | * Extracts an inner type if T has a single key K, otherwise it returns T. 8 | */ 9 | export type ExtractSingleKey> = IsUnion extends true ? T : T[KWithoutTypename] 10 | -------------------------------------------------------------------------------- /packages/vue-apollo-composable/src/util/ReactiveFunction.ts: -------------------------------------------------------------------------------- 1 | export type ReactiveFunction = () => TParam 2 | -------------------------------------------------------------------------------- /packages/vue-apollo-composable/src/util/env.ts: -------------------------------------------------------------------------------- 1 | export const isServer = typeof window === 'undefined' 2 | -------------------------------------------------------------------------------- /packages/vue-apollo-composable/src/util/paramToReactive.ts: -------------------------------------------------------------------------------- 1 | import type { Ref } from 'vue-demi' 2 | import type { ReactiveFunction } from './ReactiveFunction' 3 | import { computed, isRef, reactive } from 'vue-demi' 4 | 5 | type TObject = object 6 | 7 | export function paramToReactive(param: T | Ref | ReactiveFunction): T | Ref { 8 | if (isRef(param)) { 9 | return param 10 | } 11 | else if (typeof param === 'function') { 12 | return computed(param as ReactiveFunction) 13 | } 14 | else if (param) { 15 | return reactive(param) as T 16 | } 17 | else { 18 | return param 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /packages/vue-apollo-composable/src/util/paramToRef.ts: -------------------------------------------------------------------------------- 1 | import type { Ref } from 'vue-demi' 2 | import type { ReactiveFunction } from './ReactiveFunction' 3 | import { computed, isRef, ref } from 'vue-demi' 4 | 5 | export function paramToRef(param: T | Ref | ReactiveFunction): Ref { 6 | if (isRef(param)) { 7 | return param 8 | } 9 | else if (typeof param === 'function') { 10 | return computed(param as ReactiveFunction) 11 | } 12 | else { 13 | return ref(param) as Ref 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /packages/vue-apollo-composable/src/util/toApolloError.ts: -------------------------------------------------------------------------------- 1 | import type { GraphQLFormattedError } from 'graphql' 2 | import { ApolloError, isApolloError } from '@apollo/client/core/index.js' 3 | 4 | export function toApolloError(error: unknown): ApolloError { 5 | if (!(error instanceof Error)) { 6 | return new ApolloError({ 7 | networkError: Object.assign(new Error((error as any)?.message), { originalError: error }), 8 | errorMessage: String(error), 9 | }) 10 | } 11 | 12 | if (isApolloError(error)) { 13 | return error 14 | } 15 | 16 | return new ApolloError({ networkError: error, errorMessage: error.message }) 17 | } 18 | 19 | export function resultErrorsToApolloError(errors: ReadonlyArray): ApolloError { 20 | return new ApolloError({ 21 | graphQLErrors: errors, 22 | errorMessage: `GraphQL response contains errors: ${errors.map((e: any) => e.message).join(' | ')}`, 23 | }) 24 | } 25 | -------------------------------------------------------------------------------- /packages/vue-apollo-composable/src/util/useEventHook.ts: -------------------------------------------------------------------------------- 1 | export function useEventHook() { 2 | const fns: Array<(...params: TParams) => void> = [] 3 | 4 | function on(fn: (...params: TParams) => void) { 5 | fns.push(fn) 6 | return { 7 | off: () => off(fn), 8 | } 9 | } 10 | 11 | function off(fn: (...params: TParams) => void) { 12 | const index = fns.indexOf(fn) 13 | if (index !== -1) { 14 | fns.splice(index, 1) 15 | } 16 | } 17 | 18 | function trigger(...params: TParams) { 19 | for (const fn of fns) { 20 | fn(...params) 21 | } 22 | } 23 | 24 | function getCount() { 25 | return fns.length 26 | } 27 | 28 | return { 29 | on, 30 | off, 31 | trigger, 32 | getCount, 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /packages/vue-apollo-composable/tests/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | rules: { 3 | '@typescript-eslint/no-unused-expressions': 'off', 4 | '@typescript-eslint/no-floating-promises': 'off', 5 | '@typescript-eslint/naming-convention': 'off', 6 | '@typescript-eslint/no-unused-vars': 'off', 7 | }, 8 | } 9 | -------------------------------------------------------------------------------- /packages/vue-apollo-composable/tests/types/assertions.ts: -------------------------------------------------------------------------------- 1 | export type ExactType = T extends U ? (U extends T ? T : never) : never 2 | 3 | /** 4 | * Verify that a type matches an exact expected type. 5 | * 6 | * NOTE: Some cases don't work (like `any`, `unknown`) due to how typescript 7 | * widens types. Manually verify the assert is reliable when using. 8 | */ 9 | export function assertExactType(expected: ExactType) {} 10 | -------------------------------------------------------------------------------- /packages/vue-apollo-composable/tests/types/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "module": "commonjs", 5 | "strict": true, 6 | "noEmit": true, 7 | "esModuleInterop": true, 8 | "skipLibCheck": true 9 | }, 10 | "include": [ 11 | "*.test.ts" 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /packages/vue-apollo-composable/tests/types/useApolloClient-types.test.ts: -------------------------------------------------------------------------------- 1 | import type { UseApolloClientReturn } from '../../src' 2 | import { useApolloClient } from '../../src' 3 | import { assertExactType } from './assertions' 4 | 5 | // ============================================================================= 6 | // With no type and no clientId 7 | // - the store type should be `any` 8 | // ============================================================================= 9 | { 10 | const noClientId = useApolloClient() 11 | noClientId.client?.extract(true).storeType.is.any 12 | } 13 | 14 | // ============================================================================= 15 | // With no type and a clientId 16 | // - the store type should be `any` 17 | // ============================================================================= 18 | { 19 | const withClientId = useApolloClient('88K2tP') 20 | withClientId.client?.extract(true).storeType.is.any 21 | } 22 | 23 | // ============================================================================= 24 | // With specific type and a client id 25 | // - the store type should be the specified tyep 26 | // ============================================================================= 27 | { 28 | const withType = useApolloClient<'cacheShape'>('38pX2d') 29 | const store = withType.client?.extract(true) 30 | 31 | assertExactType>(withType) 32 | assertExactType(store) 33 | } 34 | -------------------------------------------------------------------------------- /packages/vue-apollo-composable/tests/types/util/ExtractSingleKey.test.ts: -------------------------------------------------------------------------------- 1 | import type { ExtractSingleKey, IsUnion } from '../../../src/util/ExtractSingleKey' 2 | import type { MultiKeyExampleQuery, SingleKeyExampleQuery } from '../../fixtures/graphql-example-types' 3 | import { assertExactType } from '../assertions' 4 | 5 | // IsUnion 6 | 7 | // When the type is a union, it should return true 8 | const trueUnion: IsUnion<'id' | 'name'> = true 9 | const numberTrueUnion: IsUnion<15 | 18> = true 10 | 11 | // When the type is not a union, it should return false 12 | const falseUnion: IsUnion<'id'> = false 13 | const numberFalseUnion: IsUnion<15> = false 14 | const arrayUnion: IsUnion<[string, number]> = false 15 | 16 | // When the type is never, it should return never 17 | let what: IsUnion 18 | assertExactType(what) 19 | 20 | // ExtractSingleKey 21 | 22 | // When the passed in type has a single key, it should return the type of that key 23 | let singleKeyQuery: ExtractSingleKey 24 | assertExactType(singleKeyQuery) 25 | 26 | // When the passed in type has multiple keys, it should return the type 27 | let multiKeyQuery: ExtractSingleKey 28 | assertExactType(multiKeyQuery) 29 | -------------------------------------------------------------------------------- /packages/vue-apollo-composable/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "lib": [ 5 | "DOM", 6 | "ES2020", 7 | "ES2020.Symbol.WellKnown" 8 | ], 9 | "moduleResolution": "node", 10 | "strict": true, 11 | "declaration": true, 12 | "outDir": "dist", 13 | "sourceMap": true, 14 | "allowSyntheticDefaultImports": true, 15 | "skipLibCheck": true 16 | }, 17 | "include": [ 18 | "src/**/*" 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /packages/vue-apollo-composable/tsconfig.lint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "include": [ 4 | "**/*" 5 | ], 6 | "exclude": [ 7 | "node_modules/**/*", 8 | "dist/**/*" 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /packages/vue-apollo-option/.npmignore: -------------------------------------------------------------------------------- 1 | src/ 2 | types/test/ 3 | tests/ 4 | .babelrc 5 | .eslintrc.js 6 | -------------------------------------------------------------------------------- /packages/vue-apollo-option/README.md: -------------------------------------------------------------------------------- 1 | # Apollo and GraphQL for Vue.js (Options API) 2 | 3 | [![npm](https://img.shields.io/npm/v/@vue/apollo-option.svg) ![npm](https://img.shields.io/npm/dm/@vue/apollo-option.svg)](https://www.npmjs.com/package/@vue/apollo-option) 4 | [![apollo3](https://img.shields.io/badge/apollo-3.x-blue.svg)](https://www.apollographql.com/) 5 | [![vue3](https://img.shields.io/badge/vue-3-brightgreen.svg)](https://vuejs.org/) 6 | [![CircleCI branch](https://img.shields.io/circleci/build/github/vuejs/vue-apollo/v4.svg)](https://circleci.com/gh/vuejs/vue-apollo/tree/v4) 7 | 8 |

9 | 10 |

11 | 12 | :book: Documentation [**for Vue 3**](http://v4.apollo.vuejs.org) | [for Vue 2](https://apollo.vuejs.org/) 13 | 14 | [:pen: Contributing guide](./CONTRIBUTING.md) 15 | 16 | [:heart: Sponsor me!](https://github.com/sponsors/Akryum) 17 | 18 | ```bash 19 | npm i @vue/apollo-option 20 | pnpm i @vue/apollo-option 21 | yarn add @vue/apollo-option 22 | ``` 23 | 24 | ## Sponsors 25 | 26 |

27 | 28 | 29 | 30 |

31 | -------------------------------------------------------------------------------- /packages/vue-apollo-option/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | [require('@babel/preset-env'), { modules: false }], 4 | ], 5 | plugins: [ 6 | require('@babel/plugin-proposal-class-properties'), 7 | [require('@babel/plugin-transform-for-of'), { assumeArray: true }], 8 | ], 9 | } 10 | -------------------------------------------------------------------------------- /packages/vue-apollo-option/build/rollup.config.base.js: -------------------------------------------------------------------------------- 1 | import babel from 'rollup-plugin-babel' 2 | import cjs from 'rollup-plugin-commonjs' 3 | import resolve from 'rollup-plugin-node-resolve' 4 | import replace from 'rollup-plugin-replace' 5 | 6 | const config = require('../package.json') 7 | 8 | export default { 9 | input: 'src/index.js', 10 | plugins: [ 11 | resolve({ 12 | jsnext: true, 13 | main: true, 14 | browser: true, 15 | }), 16 | cjs({ 17 | exclude: 'src/**', 18 | }), 19 | babel({ 20 | exclude: 'node_modules/**', 21 | }), 22 | replace({ 23 | VERSION: JSON.stringify(config.version), 24 | }), 25 | ], 26 | external: ['@apollo/client', 'graphql-tag'], 27 | } 28 | -------------------------------------------------------------------------------- /packages/vue-apollo-option/build/rollup.config.browser.js: -------------------------------------------------------------------------------- 1 | import { uglify } from 'rollup-plugin-uglify' 2 | import { minify } from 'uglify-es' 3 | import base from './rollup.config.base' 4 | 5 | const config = Object.assign({}, base, { 6 | output: { 7 | file: 'dist/vue-apollo-option.min.js', 8 | format: 'iife', 9 | name: 'VueApollo', 10 | }, 11 | }) 12 | 13 | config.plugins.push(uglify({}, minify)) 14 | 15 | export default config 16 | -------------------------------------------------------------------------------- /packages/vue-apollo-option/build/rollup.config.es.js: -------------------------------------------------------------------------------- 1 | import base from './rollup.config.base' 2 | 3 | const config = Object.assign({}, base, { 4 | output: { 5 | file: 'dist/vue-apollo-option.esm.mjs', 6 | format: 'es', 7 | name: 'vue-apollo', 8 | }, 9 | }) 10 | 11 | export default config 12 | -------------------------------------------------------------------------------- /packages/vue-apollo-option/build/rollup.config.umd.js: -------------------------------------------------------------------------------- 1 | import base from './rollup.config.base' 2 | 3 | const config = Object.assign({}, base, { 4 | output: { 5 | file: 'dist/vue-apollo-option.umd.js', 6 | format: 'umd', 7 | name: 'vue-apollo', 8 | }, 9 | }) 10 | 11 | export default config 12 | -------------------------------------------------------------------------------- /packages/vue-apollo-option/lib/consts.js: -------------------------------------------------------------------------------- 1 | exports.VUE_APOLLO_QUERY_KEYWORDS = [ 2 | 'variables', 3 | 'watch', 4 | 'update', 5 | 'result', 6 | 'error', 7 | 'loadingKey', 8 | 'watchLoading', 9 | 'skip', 10 | 'throttle', 11 | 'debounce', 12 | 'subscribeToMore', 13 | 'prefetch', 14 | 'manual', 15 | ] 16 | -------------------------------------------------------------------------------- /packages/vue-apollo-option/lib/utils.js: -------------------------------------------------------------------------------- 1 | const TD = require('throttle-debounce') 2 | 3 | function factory(action) { 4 | return (cb, time) => action(time, cb) 5 | } 6 | 7 | exports.throttle = factory(TD.throttle) 8 | 9 | exports.debounce = factory(TD.debounce) 10 | 11 | exports.reapply = function (options, context) { 12 | while (typeof options === 'function') { 13 | options = options.call(context) 14 | } 15 | return options 16 | } 17 | 18 | exports.omit = function (obj, properties) { 19 | return Object.entries(obj) 20 | .filter(([key]) => !properties.includes(key)) 21 | .reduce((c, [key, val]) => { 22 | c[key] = val 23 | return c 24 | }, {}) 25 | } 26 | 27 | exports.addGqlError = function (error) { 28 | if (error.graphQLErrors && error.graphQLErrors.length) { 29 | error.gqlError = error.graphQLErrors[0] 30 | } 31 | } 32 | 33 | exports.noop = () => {} 34 | -------------------------------------------------------------------------------- /packages/vue-apollo-option/src/env.js: -------------------------------------------------------------------------------- 1 | export const isServer = typeof window === 'undefined' 2 | -------------------------------------------------------------------------------- /packages/vue-apollo-option/src/index.js: -------------------------------------------------------------------------------- 1 | import { ApolloProvider } from './apollo-provider' 2 | 3 | export { ApolloProvider } from './apollo-provider' 4 | 5 | export function createApolloProvider(options) { 6 | return new ApolloProvider(options) 7 | } 8 | -------------------------------------------------------------------------------- /packages/vue-apollo-option/tests/unit/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | env: { 3 | jest: true, 4 | }, 5 | } 6 | -------------------------------------------------------------------------------- /packages/vue-apollo-option/types/.gitignore: -------------------------------------------------------------------------------- 1 | *.js 2 | -------------------------------------------------------------------------------- /packages/vue-apollo-option/types/apollo-provider.d.ts: -------------------------------------------------------------------------------- 1 | /* eslint no-unused-vars: 0 */ 2 | 3 | import type { ApolloClient } from '@apollo/client/core/index.js' 4 | import type { App, AsyncComponentOptions, ComponentOptions } from 'vue' 5 | import type { 6 | ErrorHandler, 7 | VueApolloComponentOptions, 8 | WatchLoading, 9 | } from './options' 10 | 11 | export type VueApolloComponent = VueApolloComponentOptions | AsyncComponentOptions 12 | 13 | export interface ApolloProviderOptions { 14 | defaultClient: ApolloClient 15 | defaultOptions?: VueApolloComponentOptions 16 | clients?: { [key: string]: ApolloClient } 17 | watchLoading?: WatchLoading 18 | errorHandler?: ErrorHandler 19 | prefetch?: boolean 20 | } 21 | 22 | export class ApolloProvider { 23 | constructor(options: ApolloProviderOptions) 24 | install(app: App): void 25 | 26 | clients: { [key: string]: ApolloClient } 27 | defaultClient: ApolloClient 28 | } 29 | -------------------------------------------------------------------------------- /packages/vue-apollo-option/types/index.d.ts: -------------------------------------------------------------------------------- 1 | import type { ApolloProviderOptions } from './apollo-provider' 2 | import { ApolloProvider } from './apollo-provider' 3 | import './vue' 4 | 5 | export { ApolloProvider } 6 | export function createApolloProvider(options: ApolloProviderOptions): ApolloProvider 7 | -------------------------------------------------------------------------------- /packages/vue-apollo-option/types/test/App.vue: -------------------------------------------------------------------------------- 1 | 33 | -------------------------------------------------------------------------------- /packages/vue-apollo-option/types/test/Decorator.ts: -------------------------------------------------------------------------------- 1 | import type { OperationVariables } from '@apollo/client/core' 2 | import type { VueApolloComponentOptions } from '../options' 3 | import gql from 'graphql-tag' 4 | import { Options, Vue } from 'vue-property-decorator' 5 | 6 | @Options({ 7 | apollo: { 8 | allFilms: { 9 | query: gql``, 10 | variables(): OperationVariables { 11 | return { 12 | foo: this.foo, 13 | } 14 | }, 15 | }, 16 | } as VueApolloComponentOptions, 17 | }) 18 | export default class Decorator extends Vue { 19 | allFilms = [] 20 | foo = 'bar' 21 | } 22 | -------------------------------------------------------------------------------- /packages/vue-apollo-option/types/test/index.ts: -------------------------------------------------------------------------------- 1 | import { ApolloClient, HttpLink } from '@apollo/client/core' 2 | 3 | import { createApp, h } from 'vue' 4 | import { createApolloProvider } from '../index' 5 | 6 | import App from './App' 7 | import Decorator from './Decorator' 8 | import 'isomorphic-fetch' 9 | 10 | const httpLink = new HttpLink({ uri: 'https://dummy.test.com' }) 11 | const cache: any = 'dummy cache' 12 | const apolloClient = new ApolloClient({ 13 | link: httpLink, 14 | cache, 15 | connectToDevTools: true, 16 | }) 17 | const apolloProvider = createApolloProvider({ 18 | defaultClient: apolloClient, 19 | defaultOptions: { 20 | $query: { 21 | fetchPolicy: 'cache-and-network', 22 | }, 23 | }, 24 | }) 25 | 26 | /* eslint no-new: 0 */ 27 | const app = createApp({ 28 | el: '#app', 29 | render: () => h(App, [ 30 | h(Decorator), 31 | ]), 32 | }) 33 | app.use(apolloProvider) 34 | 35 | // test to able to call below methods 36 | console.log(apolloProvider.defaultClient.query) 37 | console.log(apolloProvider.clients.key.query) 38 | -------------------------------------------------------------------------------- /packages/vue-apollo-option/types/test/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2015", 4 | "lib": [ 5 | "es5", 6 | "es6", 7 | "dom", 8 | "es2015.core", 9 | "es2015.collection", 10 | "es2015.generator", 11 | "es2015.iterable", 12 | "es2015.promise", 13 | "es2015.proxy", 14 | "es2015.reflect", 15 | "es2015.symbol", 16 | "es2015.symbol.wellknown", 17 | "esnext.asynciterable" 18 | ], 19 | "experimentalDecorators": true, 20 | "module": "es2015", 21 | "moduleResolution": "node", 22 | "allowJs": true, 23 | "strict": true, 24 | "noImplicitAny": true, 25 | "allowSyntheticDefaultImports": true, 26 | "skipLibCheck": true 27 | }, 28 | "include": [ 29 | "*.ts", 30 | "../*.d.ts" 31 | ] 32 | } 33 | -------------------------------------------------------------------------------- /packages/vue-apollo-option/types/utils.d.ts: -------------------------------------------------------------------------------- 1 | export type DeepApplyThisType = { [K in keyof T]: DeepApplyThisType } & ThisType 2 | -------------------------------------------------------------------------------- /packages/vue-apollo-option/types/vue.d.ts: -------------------------------------------------------------------------------- 1 | import type { ApolloProvider } from './apollo-provider' 2 | import type { VueApolloComponentOptions } from './options' 3 | import type { DollarApollo } from './vue-apollo' 4 | 5 | declare module 'vue' { 6 | interface ComponentOptionsBase< 7 | Props, 8 | RawBindings, 9 | D, 10 | C extends ComputedOptions, 11 | M extends MethodOptions, 12 | Mixin extends ComponentOptionsMixin, 13 | Extends extends ComponentOptionsMixin, 14 | E extends EmitsOptions, 15 | EE extends string = string, 16 | Defaults = object, 17 | > { 18 | apolloProvider?: ApolloProvider 19 | apollo?: VueApolloComponentOptions> 20 | } 21 | 22 | interface ComponentCustomProperties { 23 | $apolloProvider: ApolloProvider 24 | $apollo: DollarApollo 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /packages/vue-apollo-option/vitest.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vitest/config' 2 | 3 | export default defineConfig({ 4 | test: { 5 | globals: true, 6 | }, 7 | }) 8 | -------------------------------------------------------------------------------- /packages/vue-apollo-ssr/README.md: -------------------------------------------------------------------------------- 1 | # Server-Side Rendering Utilities for Vue Apollo 2 | 3 | [![npm](https://img.shields.io/npm/v/@vue/apollo-ssr.svg) ![npm](https://img.shields.io/npm/dm/@vue/apollo-ssr.svg)](https://www.npmjs.com/package/@vue/apollo-ssr) 4 | [![apollo3](https://img.shields.io/badge/apollo-3.x-blue.svg)](https://www.apollographql.com/) 5 | [![vue3](https://img.shields.io/badge/vue-3-brightgreen.svg)](https://vuejs.org/) 6 | [![CircleCI branch](https://img.shields.io/circleci/build/github/vuejs/vue-apollo/v4.svg)](https://circleci.com/gh/vuejs/vue-apollo/tree/v4) 7 | 8 |

9 | 10 |

11 | 12 | :book: Documentation [**for Vue 3**](http://v4.apollo.vuejs.org) | [for Vue 2](https://apollo.vuejs.org/) 13 | 14 | [:pen: Contributing guide](./CONTRIBUTING.md) 15 | 16 | [:heart: Sponsor me!](https://github.com/sponsors/Akryum) 17 | 18 | ```bash 19 | npm i @vue/apollo-ssr 20 | yarn add @vue/apollo-ssr 21 | ``` 22 | 23 | ## Sponsors 24 | 25 |

26 | 27 | 28 | 29 |

30 | -------------------------------------------------------------------------------- /packages/vue-apollo-ssr/build.mjs: -------------------------------------------------------------------------------- 1 | import fs from 'node:fs' 2 | import path from 'node:path' 3 | import process from 'node:process' 4 | 5 | const file = path.join(process.cwd(), 'dist', 'esm', 'package.json') 6 | 7 | fs.writeFileSync(file, JSON.stringify({ 8 | type: 'module', 9 | }, null, 2), 'utf-8') 10 | -------------------------------------------------------------------------------- /packages/vue-apollo-ssr/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "module": "ESNext", 5 | "moduleResolution": "node", 6 | "strict": true, 7 | "sourceMap": true, 8 | "esModuleInterop": true, 9 | "skipLibCheck": true 10 | }, 11 | "include": [ 12 | "src/**/*" 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /packages/vue-apollo-util/README.md: -------------------------------------------------------------------------------- 1 | # Utilities for Vue Apollo 2 | 3 | [![npm](https://img.shields.io/npm/v/@vue/apollo-util.svg) ![npm](https://img.shields.io/npm/dm/@vue/apollo-util.svg)](https://www.npmjs.com/package/@vue/apollo-util) 4 | [![apollo3](https://img.shields.io/badge/apollo-3.x-blue.svg)](https://www.apollographql.com/) 5 | [![vue3](https://img.shields.io/badge/vue-3-brightgreen.svg)](https://vuejs.org/) 6 | [![CircleCI branch](https://img.shields.io/circleci/build/github/vuejs/vue-apollo/v4.svg)](https://circleci.com/gh/vuejs/vue-apollo/tree/v4) 7 | 8 |

9 | 10 |

11 | 12 | :book: Documentation [**for Vue 3**](http://v4.apollo.vuejs.org) | [for Vue 2](https://apollo.vuejs.org/) 13 | 14 | [:pen: Contributing guide](./CONTRIBUTING.md) 15 | 16 | [:heart: Sponsor me!](https://github.com/sponsors/Akryum) 17 | 18 | ```bash 19 | npm i @vue/apollo-util 20 | pnpm i @vue/apollo-util 21 | yarn add @vue/apollo-util 22 | ``` 23 | 24 | ## Sponsors 25 | 26 |

27 | 28 | 29 | 30 |

31 | -------------------------------------------------------------------------------- /packages/vue-apollo-util/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@vue/apollo-util", 3 | "version": "4.2.2", 4 | "description": "Apollo GraphQL for Vue - Utilities", 5 | "author": "Guillaume Chau ", 6 | "license": "MIT", 7 | "homepage": "https://apollo.vuejs.org/", 8 | "repository": { 9 | "type": "git", 10 | "url": "https://github.com/vuejs/vue-apollo.git", 11 | "directory": "packages/vue-apollo-util" 12 | }, 13 | "bugs": { 14 | "url": "https://github.com/vuejs/vue-apollo/issues" 15 | }, 16 | "keywords": [ 17 | "vue", 18 | "apollo", 19 | "graphql", 20 | "util" 21 | ], 22 | "publishConfig": { 23 | "access": "public" 24 | }, 25 | "exports": { 26 | ".": { 27 | "types": "./dist/esm/index.d.ts", 28 | "import": "./dist/esm/index.js", 29 | "require": "./dist/cjs/index.js" 30 | }, 31 | "./*": "./*" 32 | }, 33 | "main": "dist/cjs/index.js", 34 | "types": "dist/esm/index.d.ts", 35 | "files": [ 36 | "dist" 37 | ], 38 | "scripts": { 39 | "dev": "pnpm run build --watch", 40 | "build": "rm -rf dist && tsc --outDir dist/esm -d && tsc --outDir dist/cjs --module commonjs --target ES2017", 41 | "prepublishOnly": "pnpm run build" 42 | }, 43 | "devDependencies": { 44 | "@apollo/client": "^3.7.7", 45 | "graphql": "^16.6.0", 46 | "typescript": "^4.7.4" 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /packages/vue-apollo-util/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './errorLog' 2 | -------------------------------------------------------------------------------- /packages/vue-apollo-util/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "module": "ESNext", 5 | "moduleResolution": "node", 6 | "strict": true, 7 | "sourceMap": true, 8 | "esModuleInterop": true, 9 | "skipLibCheck": true 10 | }, 11 | "include": [ 12 | "src/**/*" 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /pnpm-workspace.yaml: -------------------------------------------------------------------------------- 1 | packages: 2 | - packages/* 3 | onlyBuiltDependencies: 4 | - '@apollo/protobufjs' 5 | - core-js 6 | - core-js-pure 7 | - cypress 8 | - esbuild 9 | - nodemon 10 | - vue-demi 11 | -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = {} 2 | --------------------------------------------------------------------------------