Skip to content

Importing types between apps

Tiago Nápoli edited this page Sep 19, 2019 · 3 revisions

Running vtex setup or vtex link --setup adds on your node and react package.json the definitions packages for your app dependencies.

Say you want to use vtex.some-app graphql or react types on your app. After adding this app as dependency and running vtex setup, you'll be able to import its types definitions using:

import { SomeGraphQLType, SomeReactComponentType } from 'vtex.some-app'

This way there's no need to duplicate the definitions between graphql apps and consumer apps. Also within the same app there's no need to create typescript definitions for the graphql schema files.

Non-nullable fields on GraphQL Schemas

The typescript definitions generated for the graphql schema respects the exclamation mark(!) symbol, so the following schema:

type Character {
  name: String!
}

Will be translated to:

export type Character = {
   __typename?: 'Character',
  name: Scalars['String'],
};

Whereas:

type Character {
  name: String!
}

Will become:

export type Maybe<T> = T | null;
export type Character = {
   __typename?: 'Character',
  name?: Maybe<Scalars['String']>,
};

Because of this when the field is nullable on your graphql schema and you use its type on typescript you'll have to add a null check.

Some technicalities

  • The definitions package for an app is built on builder-hub whenever the app is linked, relinked or published. The package built is available through one of the urls:
http://vtex.vteximg.com.br/_v/public/typings/v1/${vendor}.${appname}@${major}.${minor}.${patch}/public/@types/$vendor.$appname
https://${currentWorkspace}--${currentAccount}.${publicEndpoint}/_v/private/typings/linked/v1/${appID}/public/@types/${vendor}.${appname}

The first url provides the definitions package from an app already published: it's guaranteed these definitions will not change. The second one provides the definitions package from an app linked, so its types may change. When developing an app its important to keep that in mind, maybe you can run into an error because of this.

  • The definitions package is created or updated when the app is built on builder-hub, and for now the only moments in which the definitions are downloaded to your local machine environment is when vtex setup or vtex link --setup is run, so when an app "A" is linked and has its types changed you may need to run vtex setup again if you want to use the updated types on another app "B" (or inside app "A", in case you're developing a graphql + node app, more details later). In this context of types packages, vtex setup basically does:

    • Get your app dependencies
    • Add and update the urls on node/package.json and react/package.json so that if an dependency is linked the url for your link is added/updated or, otherwise, the url for the published app types is added/updated
    • Run yarn so that the newly updated and added definitions packages are downloaded to your local environment
  • If a dependency is linked the url for it will be added to package.json, but not always this behavior is desirable, sometimes you want that all urls added are from published apps, and you don't want to unlink all apps from your workspace. For this there exists vtex setup --ignore-linked. (you may want to use this right before publishing or pushing to github).

  • The URLs added are important for the build process on builder-hub, for downloading the definitions packages there. If these types are not available, your typescript code may not compile (for example, you may import a type from an app package whose url wasn't on package.json). The only exception for this rule is when types are imported within the same app: in this case the url on package.json is only useful for downloading the types locally for developer use - in builder-hub this url is even removed from package.json.

Importing types within the same app

When developing a node and graphql app, you may use the generated graphql types on the node portion of your app through: import { SomeGraphQLType } from 'vtex.your-app-name'. These types are only generated when the app is linked or published though, so if you want to update or create new types on your graphql schemas and use them on your node code right away you'll have to:

  • Link your app
  • Run vtex setup (so the url for your app is updated to point to your link and yarn downloads the definitions package locally) Only then the new types will be available for use. Unfortunately (for now) every time you change your graphql schema and want to use these type changes on node you'll have to run vtex setup (while your app is linked, so the new types are built).

Possible errors

A new error added forbids intersection between the definitions generated for react and graphql, you'll have to rename these types on your graphql schemas or rename your react component filename:

Types generated for react and graphql intersects. Change the component filename or the graphql type name for these elements: Type1, Type2, ...

New errors on builder-hub were added to avoid common mistakes on definitions packages urls on package.json, running vtex setup should fix them:

Error on ${builder} package.json: Types for vendor.appname@version specify a linked app, but this is unallowed on publish

The following error occurs when your current workspace/account differs from the workspace/account defined on the types url at ${builder} package.json:

Error on ${builder} package.json: Inconsistent app context for vendor.appname@version types:
Expected workspace1 for workspace but received another-workspace
Expected account1 for account but received another-account
Error on ${builder} package.json: App vendor.appname@version on ${builder} package.json not found
Error on ${builder} package.json: App vendor.appname@version is not linked anymore, but types for it on ${builder} package.json specify a linked app

Some types, like Upload, are types injected by the framework, so they can't be defined on your schema. If you do so the following error will be thrown:

Error generating GraphQL types: ${TypeName} is already defined by the framework. Please remove its definition.

Technical Overview

On building an app, say vendor.appname@1.0.0, builder-hub creates a folder @types/vendor.appname where the types generated for graphql and react will be placed. The folder organization will be:

.
+-- graphql
|   +-- __types_entrypoint.d.ts
+-- react
|   +-- __types_entrypoint.d.ts
|   +-- component1.d.ts
|   +-- component2.d.ts
|   ...
+-- index.d.ts
+-- package.json

When an app is published this folder is available for download (.tar.gz file) through http://vtex.vteximg.com.br/_v/public/typings/v1/vendor.appname@1.0.0/public/@types/vendor.appname. If the app is linked this folder (updated with the link changes) will be available on https://${currentWorkspace}--${currentAccount}.${publicEndpoint}/_v/private/typings/linked/v1/${appID}/public/@types/vendor.appname (where publicEndpoint is either myvtex.com or myvtexdev.com, and appID has the format ${vendor}.${appname}@${major}.${minor}.${patch}+build${buildNumber}).

These urls are added to devDependencies on node's and/or react's package.json, for example:

{
    "devDependencies": {
        "vtex.some-app": "http://vtex.vteximg.com.br/_v/public/typings/v1/vtex.some-app@1.0.0/public/@types/vtex.some-app",
        "vtex.another-app": "https://myworkspace--myaccount.myvtex.com/_v/private/typings/linked/v1/vtex.another-app@1.0.0+build123/public/@types/vtex.another-app"
    }
}

This way when yarn is run these types packages are downloaded to node_modules and will be available in folders named with the respective key field (in the example there will be folders vtex.some-app and vtex.another-app available inside node_modules, you can peek them and check if the types are as you expect).