Browse Source

docs: Various documentation improvements

Michael Bromley 4 years ago
parent
commit
6bc01aae23

+ 4 - 0
docs/content/developer-guide/channels.md

@@ -21,6 +21,10 @@ Use-cases of Channels include:
 * Creating distinct rules and inventory for different sales channels such as Amazon.
 * Specialized stores offering a subset of the main inventory.
 
+## How to set the channel when using the GraphQL API
+
+To specify which channel to use when making an API call, set the `'vendure-token'` header to match the token of the desired Channel.
+
 ## Multi-Tenant (Marketplace) Support
 
 Channels can also be used to implement a multi-tenant or marketplace application. In such a setup, each merchant would have their own dedicated Channel and would be granted permissions on that Channel only.

+ 18 - 0
docs/content/developer-guide/deployment.md

@@ -34,6 +34,24 @@ For a production Vendure server, there are a few security-related points to cons
   ```
 * Consider using [helmet](https://github.com/helmetjs/helmet) as middleware (add to the `apiOptions.middleware` array) to handle security-related headers. 
 
+## Serverless / multi-instance deployments
+
+Vendure supports running in a serverless or multi-instance (horizontally scaled) environment. The key consideration in configuring Vendure for this scenario is to ensure that any persistent state is managed externally from the Node process, and is shared by all instances. Namely:
+
+* The JobQueue should be stored externally using the [DefaultJobQueuePlugin]({{< relref "default-job-queue-plugin" >}}) (which stores jobs in the database) or the [BullMQJobQueuePlugin]({{< relref "bull-mqjob-queue-plugin" >}}) (which stores jobs in Redis), or some other custom JobQueueStrategy.
+* A custom [SessionCacheStrategy]({{< relref "session-cache-strategy" >}}) must be used which stores the session cache externally (such as in the database or Redis), since the default strategy stores the cache in-memory and will cause inconsistencies in multi-instance setups.
+* When using cookies to manage sessions, make sure all instances are using the _same_ cookie secret:
+    ```TypeScript
+    const config: VendureConfig = {
+      authOptions: {
+        cookieOptions: {
+          secret: 'some-secret'
+        }
+      }
+    }
+    ```
+* Channel and Zone data gets cached in-memory as this data is used in virtually every request. The cache time-to-live defaults to 30 seconds, which is probably fine for most cases, but it can be configured in the [EntityOptions]({{< relref "entity-options" >}}#channelcachettl).
+
 ## Health/Readiness Checks
 
 If you wish to deploy with Kubernetes or some similar system, you can make use of the health check endpoints. 

+ 15 - 18
docs/content/storefront/building-a-storefront/_index.md

@@ -10,35 +10,32 @@ The storefront is the application which customers use to buy things from your st
 
 As a headless server, Vendure provides a GraphQL API and Admin UI app, but no storefront. The key advantage of the headless model is that the storefront (or indeed, any number of client applications) can be developed completely independently of the server. This flexibility comes at the cost of having to build and maintain your own storefront.
 
-Essentially, you can use **any technology** to build your storefront. Here are some suggestions you may wish to investigate:
+Luckily there are some projects that can help you get your storefront up-and-running quickly:
 
-## Angular / Vendure Storefront
 
-{{< figure src="./vendure-storefront-screenshot-01.jpg" >}}
-
-This is an example storefront PWA application built with Angular. If you have Angular experience you may wish to use this as the basis of your own storefront implementation.
-
-A live demo can be found here: [demo.vendure.io/storefront/](https://demo.vendure.io/storefront/)
+## Vue Storefront
 
-Keep up with development here: [github.com/vendure-ecommerce/storefront](https://github.com/vendure-ecommerce/storefront)
+{{< figure src="./vue-storefront-logo.png" >}}
 
-## Next.js
+[Vue Storefront](https://www.vuestorefront.io/) is a popular backend-agnostic storefront PWA solution and they offer an official [Vue Storefront Vendure integration](https://docs.vuestorefront.io/vendure/).
 
-[Next.js](https://nextjs.org/) is a popular React-based framework which many Vendure developers have chosen as the basis of their storefront application. The team behind Next.js are also working on an e-commerce-specific solution, [Next.js Commerce](https://nextjs.org/commerce), which is currently under development but is worth keeping an eye on.
+For step-by-step instructions see our [Vue Storefront integration blog post]({{< relref "/blog/2021-10-13-announcing-vendure-1-3/index.md" >}}).
 
-## Vue / Nuxt
+## Next.js Commerce
+ 
+{{< figure src="./vercel-commerce-screenshot.webp" >}}
 
-[Nuxt](https://nuxtjs.org/) is a framework based on [Vue](https://vuejs.org/) with a focus on developer experience and has support for PWA, server-side rendering and static content generation.
+[Next.js](https://nextjs.org/) is a popular React-based framework which many Vendure developers have chosen as the basis of their storefront application. The team behind Next.js have created an e-commerce-specific solution, [Next.js Commerce](https://nextjs.org/commerce), and it includes an official [Vendure integration](https://github.com/vercel/commerce/tree/main/framework/vendure)
 
+[Next.js Commerce Vendure integration demo](https://vendure.vercel.store/)
 
-## Vue Storefront
 
-[Vue Storefront](https://www.vuestorefront.io/) is a popular backend-agnostic storefront PWA solution. They offer documentation on connecting their frontend application with a custom backend such as Vendure: https://github.com/DivanteLtd/vue-storefront-integration-sdk
+## Angular Demo Storefront
 
-## Gatsby
+{{< figure src="./vendure-storefront-screenshot-01.jpg" >}}
 
-[Gatsby](https://www.gatsbyjs.org/) is a popular React-based static site generator. We have developed a Gatsby-based storefront app: [vendure-ecommerce/gatsby-storefront](https://github.com/vendure-ecommerce/gatsby-storefront). This is a minimal proof-of-concept which can be used as the starting point for your own Gatsby-based storefront.
+This is an example storefront PWA application built with Angular. If you have Angular experience you may wish to use this as the basis of your own storefront implementation.
 
-## Svelte / Sapper
+A live demo can be found here: [demo.vendure.io/storefront/](https://demo.vendure.io/storefront/)
 
-[Sapper](https://sapper.svelte.dev/) is a framework based on [Svelte](https://svelte.dev/), and focuses on high-performance and supports server-rendering.
+Keep up with development here: [github.com/vendure-ecommerce/storefront](https://github.com/vendure-ecommerce/storefront)

BIN
docs/content/storefront/building-a-storefront/vercel-commerce-screenshot.webp


BIN
docs/content/storefront/building-a-storefront/vue-storefront-logo.png


+ 2 - 1
packages/common/src/shared-types.ts

@@ -58,7 +58,8 @@ export type JsonCompatible<T> = {
 
 /**
  * @description
- * A type describing the shape of a paginated list response.
+ * A type describing the shape of a paginated list response. In Vendure, almost all list queries
+ * (`products`, `collections`, `orders`, `customers` etc) return an object of this type.
  *
  * @docsCategory common
  */

+ 1 - 0
packages/core/src/config/vendure-config.ts

@@ -778,6 +778,7 @@ export interface JobQueueOptions {
  * Options relating to the internal handling of entities.
  *
  * @since 1.3.0
+ * @docsCategory configuration
  */
 export interface EntityOptions {
     /**

+ 1 - 0
packages/core/src/job-queue/job-buffer/job-buffer-storage-strategy.ts

@@ -7,6 +7,7 @@ import { Job } from '../job';
  * {@link JobBuffer}.
  *
  * @since 1.3.0
+ * @docsCategory job-queue
  */
 export interface JobBufferStorageStrategy extends InjectableStrategy {
     /**

+ 21 - 0
packages/core/src/job-queue/job-buffer/job-buffer.ts

@@ -56,6 +56,27 @@ import { JobData } from '../types';
  * }
  * ```
  *
+ * A JobBuffer is used by adding it to the {@link JobQueueService}, at which point it will become active
+ * and start collecting jobs.
+ *
+ * At some later point, the buffer can be flushed, causing the buffered jobs to be passed through the
+ * `reduce()` method and sent to the job queue.
+ *
+ * @example
+ * ```TypeScript
+ * const collectionBuffer = new CollectionJobBuffer();
+ *
+ * await this.jobQueueService.addBuffer(collectionBuffer);
+ *
+ * // Here you can perform some work which would ordinarily
+ * // trigger the 'apply-collection-filters' job, such as updating
+ * // collection filters or changing ProductVariant prices.
+ *
+ * await this.jobQueueService.flush(collectionBuffer);
+ *
+ * await this.jobQueueService.removeBuffer(collectionBuffer);
+ * ```
+ *
  * @docsCategory JobQueue
  * @since 1.3.0
  */

+ 43 - 1
packages/core/src/plugin/default-job-queue-plugin/default-job-queue-plugin.ts

@@ -19,9 +19,51 @@ import { SqlJobQueueStrategy } from './sql-job-queue-strategy';
  * @docsPage DefaultJobQueuePlugin
  */
 export interface DefaultJobQueueOptions {
+    /**
+     * @description
+     * The interval in ms between polling the database for new jobs. If many job queues
+     * are active, the polling may cause undue load on the database, in which case this value
+     * should be increased to e.g. 1000.
+     *
+     * @description 200
+     */
     pollInterval?: number | ((queueName: string) => number);
+    /**
+     * @description
+     * How many jobs from a given queue to process concurrently.
+     *
+     * @default 1
+     */
     concurrency?: number;
+    /**
+     * @description
+     * The strategy used to decide how long to wait before retrying a failed job.
+     *
+     * @default () => 1000
+     */
     backoffStrategy?: BackoffStrategy;
+    /**
+     * @description
+     * When a job is added to the JobQueue using `JobQueue.add()`, the calling
+     * code may specify the number of retries in case of failure. This option allows
+     * you to override that number and specify your own number of retries based on
+     * the job being added.
+     *
+     * @example
+     * ```TypeScript
+     * setRetries: (queueName, job) => {
+     *   if (queueName === 'send-email') {
+     *     // Override the default number of retries
+     *     // for the 'send-email' job because we have
+     *     // a very unreliable email service.
+     *     return 10;
+     *   }
+     *   return job.retries;
+     * }
+     *  ```
+     * @param queueName
+     * @param job
+     */
     setRetries?: (queueName: string, job: Job) => number;
     /**
      * @description
@@ -109,7 +151,7 @@ export interface DefaultJobQueueOptions {
  *         // A default delay for all other queues
  *         return 1000;
  *       },
- *       retries: (queueName, job) => {
+ *       setRetries: (queueName, job) => {
  *         if (queueName === 'send-email') {
  *           // Override the default number of retries
  *           // for the 'send-email' job because we have

+ 13 - 3
packages/elasticsearch-plugin/src/options.ts

@@ -163,9 +163,8 @@ export interface ElasticsearchOptions {
      * Elasticsearch index and expose that data via the SearchResult GraphQL type,
      * adding a new `customMappings` field.
      *
-     * The `graphQlType` property may be one of `String`, `Int`, `Float`, `Boolean`, or list
-     * versions thereof (`[String!]` etc) and
-     * can be appended with a `!` to indicate non-nullable fields.
+     * The `graphQlType` property may be one of `String`, `Int`, `Float`, `Boolean`, `ID` or list
+     * versions thereof (`[String!]` etc) and can be appended with a `!` to indicate non-nullable fields.
      *
      * This config option defines custom mappings which are accessible when the "groupByProduct"
      * input options is set to `true`.
@@ -464,6 +463,17 @@ export interface SearchConfig {
      * @description
      * Sets `script_fields` inside the elasticsearch body which allows returning a script evaluation for each hit.
      *
+     * The script field definition consists of three properties:
+     *
+     * * `graphQlType`: This is the type that will be returned when this script field is queried
+     * via the GraphQL API. It may be one of `String`, `Int`, `Float`, `Boolean`, `ID` or list
+     * versions thereof (`[String!]` etc) and can be appended with a `!` to indicate non-nullable fields.
+     * * `context`: determines whether this script field is available when grouping by product. Can be
+     * `product`, `variant` or `both`.
+     * * `scriptFn`: This is the function to run on each hit. Should return an object with a `script` property,
+     * as covered in the
+     * [Elasticsearch script fields docs](https://www.elastic.co/guide/en/elasticsearch/reference/7.15/search-fields.html#script-fields)
+     *
      * @example
      * ```TypeScript
      * extendSearchInputType: {

+ 13 - 0
packages/job-queue-plugin/src/bullmq/types.ts

@@ -48,6 +48,19 @@ export interface BullMQPluginOptions {
      * you to override that number and specify your own number of retries based on
      * the job being added.
      *
+     * @example
+     * ```TypeScript
+     * setRetries: (queueName, job) => {
+     *   if (queueName === 'send-email') {
+     *     // Override the default number of retries
+     *     // for the 'send-email' job because we have
+     *     // a very unreliable email service.
+     *     return 10;
+     *   }
+     *   return job.retries;
+     * }
+     *  ```
+     *
      * @since 1.3.0
      */
     setRetries?: (queueName: string, job: Job) => number;