Browse Source

feat(docs): Add migration guide for v2

Michael Bromley 2 years ago
parent
commit
957d9d1d97

+ 2 - 2
docs/assets/styles/_menu.scss

@@ -27,7 +27,7 @@ nav.book-menu {
     }
 
     ul:not(.expanded) > .section {
-        &:nth-of-type(6) {
+        &:nth-of-type(7) {
             &::before {
                 position: absolute;
                 top: 0;
@@ -40,7 +40,7 @@ nav.book-menu {
             padding-top: 1em;
         }
 
-        &:nth-of-type(n + 6) {
+        &:nth-of-type(n + 7) {
             color: $gray-700;
         }
     }

+ 40 - 0
docs/content/migrating-from-v1/_index.md

@@ -0,0 +1,40 @@
+---
+title: "Migrating from v1"
+weight: 2
+---
+
+# Migrating from Vendure 1 to 2
+
+This section contains guides for migrating from Vendure v1 to v2.
+
+There are a number of breaking changes between the two versions, which are due to a few major factors:
+
+1. To support new features such as multi-vendor marketplace APIs and multiple stock locations, we had to make some changes to the database schema and some of the internal APIs.
+2. We have updated all of our major dependencies to their latest versions. Some of these updates involve breaking changes in the dependencies themselves, and in those cases where you are using those dependencies directly (most notably TypeORM), you will need to make the corresponding changes to your code.
+3. We have removed some old APIs which were previously marked as "deprecated".
+
+## Migration steps
+
+Migration will consist of these main steps:
+
+1. **Update your Vendure dependencies** to the latest versions
+   ```diff
+   {
+     // ...
+     "dependencies": {
+   -    "@vendure/common": "1.9.7",
+   -    "@vendure/core": "1.9.7",
+   +    "@vendure/common": "2.0.0",
+   +    "@vendure/core": "2.0.0",
+        // etc.
+     },
+     "devDependencies": {
+   -    "typescript": "4.3.5",
+   +    "typescript": "4.9.5",
+        // etc.
+     }
+   }
+   ```
+2. **Migrate your database**. This is covered in detail in the [database migration section]({{< relref "database-migration" >}}).
+3. **Update your custom code** (configuration, plugins, admin ui extensions) to handle the breaking changes. Details of these changes are covered in the [breaking API changes section]({{< relref "breaking-api-changes" >}}).
+4. **Update your storefront** to handle some small breaking changes in the Shop GraphQL API. See the [storefront migration section]({{< relref "storefront-migration" >}}) for details.

+ 210 - 0
docs/content/migrating-from-v1/breaking-api-changes.md

@@ -0,0 +1,210 @@
+---
+title: "Breaking API Changes"
+weight: 1
+---
+
+# Breaking API Changes
+
+## Breaks from updated dependencies
+
+### TypeScript
+- v2 is built on TypeScript **v4.9.5**. You should update your TypeScript version to match this. Doing so is quite likely to reveal new compiler errors (as is usual with TypeScript minor release updates).
+- If you are using `ts-node`, update it to the latest version
+- If you are targeting `ES2022` or `ESNEXT` in your `tsconfig.json`, you'll need to set `"useDefineForClassFields": false`. See [this issue](https://github.com/vendure-ecommerce/vendure/issues/2099) for more context.
+
+### Apollo Server & GraphQL
+If you have any custom ApolloServerPlugins, the plugin methods must now return a Promise. Example:
+
+```diff
+export class TranslateErrorsPlugin implements ApolloServerPlugin {
+   constructor(private i18nService: I18nService) {}
+
+-  requestDidStart(): GraphQLRequestListener {
++  async requestDidStart(): Promise<GraphQLRequestListener> {
+     return {
+-      willSendResponse: requestContext => {
++      willSendResponse: async requestContext => {
+         const { errors, context } = requestContext;
+         if (errors) {
+           (requestContext.response as any).errors = errors.map(err => {
+             return this.i18nService.translateError(context.req, err as GraphQLError) as any;
+           });
+         }
+       },
+     };
+   }
+}
+```
+
+With the update to GraphQL v16, you might run into issues with other packages in the GraphQL ecosystem that also depend on the `graphql` package, such as `graphql-code-generator`. In this case these packages will also need to be updated.
+
+For instance, if you are using the "typescript-compatibility" plugin to generate namespaced types, you'll need to drop this, as it is [no longer maintained](https://the-guild.dev/blog/whats-new-in-graphql-codegen-v2#typescript-compatibility).
+
+### TypeORM
+TypeORM 0.3.x introduced a large number of breaking changes. For a complete guide, see the [TypeORM v0.3.0 release notes](https://github.com/typeorm/typeorm/releases/tag/0.3.0). 
+
+Here are the main API changes you'll likely need to make:
+
+- You can no longer compare to `null`, you need to use the new `IsNull()` helper:
+    ```diff
+    + import { IsNull } from 'typeorm';
+
+    - .find({ where: { deletedAt: null } })
+    + .find({ where: { deletedAt: IsNull() } })
+    ```
+- The `findOne()` method returns `null` rather than `undefined` if a record is not found.
+- The `findOne()` method no longer accepts an id argument. Lookup based on id must be done with a `where` clause:
+    ```diff
+    - .findOne(variantId)
+    + .findOne({ where: { id: variantId } })
+    ```
+- Where clauses must use an entity id rather than passing an entity itself:
+    ```diff
+    - .find({ where: { user } })
+    + .find({ where: { user: { id: user.id } } })
+    ```
+- The `findByIds()` method has been deprecated. Use the new `In` helper instead:
+    ```diff
+    + import { In } from 'typeorm';
+
+    - .findByIds(ids)
+    + .find({ where: { id: In(ids) } })
+    ```
+
+## Vendure TypeScript API Changes
+
+### Custom Order / Fulfillment / Payment processes
+
+In v2, the hard-coded states & transition logic for the Order, Fulfillment and Payment state machines has been extracted from the core services and instead reside in a default `OrderProcess`, `FulfillmentProcess` and `PaymentProcess` object. This allows you to _fully_ customize these flows without having to work around the assumptions & logic implemented by the default processes.
+
+What this means is that if you are defining a custom process, you'll now need to explicitly add the default process to the array.
+
+```diff
++ import { defaultOrderProcess } from '@vendure/core';
+
+orderOptions: {
+-  process: [myCustomOrderProcess],
++  process: [defaultOrderProcess, myCustomOrderProcess],
+}
+```
+
+Also note that `shippingOptions.customFulfillmentProcess` and `paymentOptions.customPaymentProcess` are both now renamed to `process`. The old names are still usable but are deprecated.
+
+### OrderItem no longer exists
+
+As a result of [#1981](https://github.com/vendure-ecommerce/vendure/issues/1981), the `OrderItem` entity no longer exists. The function and data of `OrderItem` is now transferred to `OrderLine`. As a result, the following APIs which previously used OrderItem arguments have now changed:
+
+- `FulfillmentHandler`
+- `ChangedPriceHandlingStrategy`
+- `PromotionItemAction`
+- `TaxLineCalculationStrategy`
+
+If you have implemented any of these APIs, you'll need to check each one, remove the `OrderItem` argument from any methods that are using it,
+and update any logic as necessary.
+
+You may also be joining the OrderItem relation in your own TypeORM queries, so you'll need to check for code like this:
+
+```diff
+const order = await this.connection
+  .getRepository(Order)
+  .createQueryBuilder('order')
+  .leftJoinAndSelect('order.lines', 'line')
+- .leftJoinAndSelect('line.items', 'items')
+```
+
+or 
+
+```diff
+const order = await this.connection
+  .getRepository(Order)
+  .findOne(ctx, orderId, {
+-    relations: ['lines', 'lines.items'],
++    relations: ['lines'],
+  });
+```
+
+### ProductVariant stock changes
+
+With [#1545](https://github.com/vendure-ecommerce/vendure/issues/1545) we have changed the way we model stock levels in order to support multiple stock locations. This means that the `ProductVariant.stockOnHand` and `ProductVariant.stockAllocated` properties no longer exist on the `ProductVariant` entity in TypeScript.
+
+Instead, this information is now located at `ProductVariant.stockLevels`, which is an array of [StockLevel]({{< relref "stock-level" >}}) entities.
+
+### New return type for Channel, TaxCategory & Zone lists
+
+- The `ChannelService.findAll()` method now returns a `PaginatedList<Channel>` instead of `Channel[]`. 
+- The `channels` GraphQL query now returns a `PaginatedList` rather than a simple array of Channels.
+- The `TaxCategoryService.findAll()` method now returns a `PaginatedList<TaxCategory>` instead of `TaxCategory[]`.
+- The `taxCategories` GraphQL query now returns a `PaginatedList` rather than a simple array of TaxCategories.
+- The `ZoneService.findAll()` method now returns a `PaginatedList<Zone>` instead of `Zone[]`. The old behaviour of `ZoneService.findAll()` (all Zones, cached for rapid access) can now be found under the new `ZoneService.getAllWithMembers()` method.
+- The `zones` GraphQL query now returns a `PaginatedList` rather than a simple array of Zones. 
+
+### Admin UI changes
+
+If you are using the `@vendure/ui-devkit` package to generate custom ui extensions, here are the breaking changes to be aware of:
+
+- As part of the major refresh to the Admin UI app, certain layout elements had be changed which can cause your custom routes to look bad. Wrapping all your custom pages in <vdr-page-block> (or <div class="page-block"> if not built with Angular components) will improve things. There will soon be a comprehensive guide published on how to create seamless ui extensions that look just like the built-in screens.
+- If you use any of the scoped method of the Admin UI `DataService`, you might find that some no longer exist. They are now deprecated and will eventually be removed. Use the `dataService.query()` and `dataService.mutation()` methods only, passing your own GraphQL documents:
+   ```ts
+    // Old way
+   this.dataService.product.getProducts().single$.subscribe(...);
+   ```
+   ```ts
+    // New way
+   const GET_PRODUCTS = gql`
+     query GetProducts {
+       products {
+         items {
+           id
+           name
+           # ... etc
+         }
+       }
+     }
+   `;
+   this.dataService.query(GET_PRODUCTS).single$.subscribe(...);
+   ```
+- The Admin UI component `vdr-product-selector` has been renamed to `vdr-product-variant-selector` to more accurately represent what it does. If you are using `vdr-product-selector` if any ui extensions code, update it to use the new selector.
+
+
+### Other breaking API changes
+- Internal `ErrorResult` classes now take a single object argument rather than multiple args.
+- All monetary values are now represented in the GraphQL APIs with a new `Money` scalar type. If you use [graphql-code-generator](https://the-guild.dev/graphql/codegen), you'll want to tell it to treat this scalar as a number:
+    ```ts
+    import { CodegenConfig } from '@graphql-codegen/cli'
+ 
+    const config: CodegenConfig = {
+      schema: 'http://localhost:3000/shop-api',
+      documents: ['src/**/*graphql.ts'],
+      config: {
+        scalars: {
+          Money: 'number',
+        },
+      },
+      generates: {
+        // .. 
+      }
+    };
+    ```
+- A new `Region` entity has been introduced, which is a base class for `Country` and the new `Province` entity. The `Zone.members` property is now an array of `Region` rather than `Country`, since Zones may now be composed of both countries and provinces. If you have defined any custom fields on `Country`, you'll need to change it to `Region` in your custom fields config.
+- If you are using the **s3 storage strategy** of the AssetServerPlugin, it has been updated to use v3 of the AWS SDKs. This update introduces an [improved modular architecture to the AWS sdk](https://aws.amazon.com/blogs/developer/modular-packages-in-aws-sdk-for-javascript/), resulting in smaller bundle sizes. You need to install the `@aws-sdk/client-s3` & `@aws-sdk/lib-storage` packages, and can remove the `aws-sdk` package. If you are using it in combination with MinIO, you'll also need to rename a config property and provide a region:
+   ```diff
+   nativeS3Configuration: {
+      endpoint: 'http://localhost:9000',
+   -  s3ForcePathStyle: true,
+   +  forcePathStyle: true,
+      signatureVersion: 'v4',
+   +  region: 'eu-west-1',
+   }
+   ```
+- The **Stripe plugin** has been made channel aware. This means your api key and webhook secret are now stored in the database, per channel, instead of environment variables.
+   To migrate to v2 of the Stripe plugin from @vendure/payments you need to:
+  1. Remove the apiKey and webhookSigningSecret from the plugin initialization in vendure-config.ts:
+       ```diff
+       StripePlugin.init({
+       -  apiKey: process.env.YOUR_STRIPE_SECRET_KEY,
+       -  webhookSigningSecret: process.env.YOUR_STRIPE_WEBHOOK_SIGNING_SECRET,
+          storeCustomersInStripe: true,
+       }),
+       ```
+  2. Start the server and login as administrator. For each channel that you'd like to use Stripe payments, you need to create a payment method with payment handler Stripe payment and the apiKey and webhookSigningSecret belonging to that channel's Stripe account.
+- If you are using the **BullMQJobQueuePlugin**, the minimum Redis recommended version is 6.2.0.

+ 39 - 0
docs/content/migrating-from-v1/database-migration.md

@@ -0,0 +1,39 @@
+---
+title: "Database Migration"
+weight: 0
+---
+
+# v2 Database Migration
+
+Vendure v2 introduces a number of breaking changes to the database schema, some of which require quite complex migrations in order to preserve existing data. To make this process as smooth as possible, we have created a migration tool which will handle the hard parts for you!
+
+{{< alert "warning" >}}
+**Important!** It is _critical_ that you back up your production data prior to attempting this migration.
+
+**Note for MySQL/MariaDB users:** transactions for migrations are [not supported by these databases](https://dev.mysql.com/doc/refman/5.7/en/cannot-roll-back.html). This means that if the migration fails for some reason, the statements that have executed will not get rolled back, and your DB schema can be left in an inconsistent state from which is it can be hard to recover. Therefore, it is doubly critical that you have a good backup that you can easily restore prior to attempting this migration.
+{{< /alert >}}
+
+1. Make sure all your Vendure packages to the latest v2 versions.
+2. Use your package manager to install the [v2 migration tool](https://github.com/vendure-ecommerce/v2-migration-tool): `npm install @vendure/migrate-v2`
+    - Note, if you run into the error `"Cannot find module '@ardatan/aggregate-error'"`, delete node_modules and the lockfile and reinstall.
+3. Add the `MigrationV2Plugin` to your plugins array:
+   ```ts
+   import { MigrationV2Plugin } from '@vendure/migrate-v2';
+   
+   //...
+   const config: VendureConfig = {
+     //..
+     plugins: [
+       MigrationV2Plugin,
+     ]
+   }
+   ```
+   The sole function of this plugin is to temporarily remove some "NOT NULL" constraints from certain columns, which allows us to run the next part of the migration.
+4. Generate a new migration file, `npm run migration:generate v2`
+5. Edit the newly-created migration file by following the comments in these examples: 
+    - [postgres](https://github.com/vendure-ecommerce/v2-migration-tool/blob/master/src/migrations/1681467180672-v2-beta1-postgres.ts)
+    - [mysql](https://github.com/vendure-ecommerce/v2-migration-tool/blob/master/src/migrations/1681467211945-v2-beta1-mysql.ts)
+
+   In your migrations files, you'll import the `vendureV2Migrations` from `@vendure/migrate-v2`.
+6. Run the migration with `npm run migration:run`.
+7. Upon successful migration, remove the `MigrationV2Plugin` from your plugins array, and generate _another_ migration. This one will add back the missing "NOT NULL" constraints now that all your data has been successfully migrated.

+ 29 - 0
docs/content/migrating-from-v1/storefront-migration.md

@@ -0,0 +1,29 @@
+---
+title: "Storefront Migration"
+---
+
+# Storefront migration
+
+There are relatively few breaking changes that will affect the storefront.
+
+- The `setOrderShippingMethod` mutation now takes an array of shipping method IDs rather than just a single one. This is so we can support multiple shipping methods per Order.
+   ```diff
+   -mutation setOrderShippingMethod($shippingMethodId: ID!) {
+   +mutation setOrderShippingMethod($shippingMethodId: [ID!]!) {
+     setOrderShippingMethod(shippingMethodId: $shippingMethodId) {
+       # ... etc
+     }
+   } 
+   ```
+- The `OrderLine.fulfillments` field has been changed to `OrderLine.fulfillmentLines`. Your storefront may be using this when displaying the details of an Order.
+- If you are using the `graphql-code-generator` package to generate types for your storefront, all monetary values such as `Order.totalWithTax` or `ProductVariant.priceWithTax` are now represented by the new `Money` scalar rather than by an `Int`. You'll need to tell your codegen about this scalar and configure it to be interpreted as a number type:
+   ```diff
+   documents:
+     - "app/**/*.{ts,tsx}"
+     - "!app/generated/*"
+   +config:
+   +  scalars:
+   +    Money: number
+   generates:
+     # ... etc
+   ```