Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rewrite of Image and Files (breaking) #7070

Merged
merged 105 commits into from
May 26, 2022
Merged

Rewrite of Image and Files (breaking) #7070

merged 105 commits into from
May 26, 2022

Conversation

rohan-deshpande
Copy link
Contributor

@rohan-deshpande rohan-deshpande commented Dec 10, 2021

Warning: This new feature includes breaking changes that may affect you

This pull request replaces image and files configuration options in Keystone's configuration, and replaces them with a new storage configuration object.

  • ➕ Amazon S3 (and other compatible providers) are now supported when uploading images and files
  • ➕ New Guide coming - see Add Images and Files Guide to Keystone Docs #7563 will be merged soon but check it out if you are keen
  • 🚨 Images and files are now - DELETED BY DEFAULT from the underlying storage provider when replaced or deleted from the database
    • Note: A preserve flag has been added to the new storage configurations to default back to the previous behaviour

  • ⚠️ If you were previously using refs in your application, you need to migrate your database

How to upgrade

Previously, your images and files were managed in your root Keystone configuration, under the fields .images and .files respectively.
The underlying storage mechanism was denominated through an upload field on each respectively, and you had no easy way to modify this behaviour for different fields.

It probably looked something like this

export default config({
  image: { upload: 'local' },
  lists: {
    Image: { fields: { image: image() } },
    /* ... */
  },
  /* ... */
});

As of this pull request, there is now a unified .storage configuration object that can contain multiple different storage providers, which you can optionally share or differentiate between for different fields as desired.
A canonical example for storing some images on the local filesystem might look something like the following:

export default config({
  storage: {
    my_avatars: {
      kind: 'local',
      type: 'image',
      generateUrl: path => `http://localhost:3000/avatars${path}`,
      serverRoute: { path: '/avatars' },
      storagePath: 'public/avatars',
    },
  },
  lists: {
    User: {
		fields: {
			avatar: image({ storage: 'my_avatars' })
		}
	 },
    // ...
  },
  // ...
});

A canonical example for storing some images on an S3 compatible storage provider might look something like the following:

export default config({
  storage: {
    my_avatars: {
      kind: 's3',
      type: 'image',
      bucketName: process.env.S3_BUCKET_NAME,
      region: process.env.S3_REGION,
      accessKeyId: process.env.S3_ACCESS_KEY_ID,
      secretAccessKey: process.env.S3_SECRET_ACCESS_KEY,
    },
  },
  lists: {
    User: {
		fields: {
			avatar: image({ storage: 'my_avatars' })
		}
	 },
	// ...
  },
  // ...
});

Goodbye refs

The previous implementation of refs were useful for moving images between different lists using the admin interface, allowing a user to refer to same image or file without copying that duplicating that image or file at the storage layer.
Unfortunately, this creates a precarious and imperformant situation when you want or need to delete these images or file; you then need to undertake a form of ref-counting across your different lists in a custom hook to ensure you won't 404 the the underlying image or file.

This complexity didn't really pay off for the benefits it provided, when compared with typical Keystone relationships; and in fact the inability to use GraphQL to introspect these references was inhibitive.
The end result is images or files are left to orphan and/or duplicate themselves until some external reason results in the manual database and storage layer interventions.

With refs removed, the new recommendation for sharing images between lists and fields is an approach you may already be familiar with: Keystone Relationships.
A canonical examle for sharing an image between multiple lists might look something like the following:

export default config({
  storage: {
    my_images: {
      // ...
    },
  },
  lists: {
    Image: { fields: { image: image({ storage: 'my_images' }) } },
    User: { fields: { avatar: relationship({ ref: 'Image' }) } },
    Post: { fields: { photos: relationship({ ref: 'Image', many: true }) } },
    // ...
  },
  // ...
});

Using Keystone relationships allows you to mirror the previous functionality while supporting the needs and features required when scaling up.

What if I can't?

If you can't migrate your schema to use Keystone relationships, but you still want to update your Keystone instance to the new storage configuration, you can use preserve: true to ensure that files - that are replaced or deleted from the database - are not deleted from the underlying storage layer.
However, similar to the previous behaviour prior to this pull request, this will result in images and files becoming orphans within the relevant filesystems as they are removed from the database.

Other changes

Local images no longer need a baseUrl

If you were previously using baseUrl for your upload: 'local', the configuration approach has changed to serverRoute.path.

For example

{
-   baseUrl: '/images'
+   serverRoute: {
+       path: '/images'
+   }
}

@changeset-bot

This comment was marked as resolved.

@vercel

This comment was marked as resolved.

@codesandbox-ci

This comment was marked as outdated.

@vercel vercel bot temporarily deployed to Preview December 15, 2021 03:28 Inactive
@vercel vercel bot temporarily deployed to Preview February 2, 2022 04:18 Inactive
@vercel vercel bot temporarily deployed to Preview February 2, 2022 04:24 Inactive
@vercel vercel bot temporarily deployed to Preview February 3, 2022 00:21 Inactive
@vercel vercel bot temporarily deployed to Preview February 3, 2022 00:33 Inactive
@vercel vercel bot temporarily deployed to Preview February 3, 2022 01:10 Inactive
@vercel vercel bot temporarily deployed to Preview February 3, 2022 01:24 Inactive
@vercel vercel bot temporarily deployed to Preview February 3, 2022 01:31 Inactive
@vercel vercel bot temporarily deployed to Preview February 3, 2022 01:44 Inactive
@vercel vercel bot temporarily deployed to Preview February 3, 2022 04:24 Inactive
@vercel vercel bot temporarily deployed to Preview February 3, 2022 04:28 Inactive
@vercel vercel bot temporarily deployed to Preview February 3, 2022 04:35 Inactive
@vercel vercel bot temporarily deployed to Preview February 3, 2022 04:39 Inactive
@vercel vercel bot temporarily deployed to Preview February 3, 2022 04:43 Inactive
@vercel vercel bot temporarily deployed to Preview February 3, 2022 04:48 Inactive
@vercel vercel bot temporarily deployed to Preview February 3, 2022 05:00 Inactive
@vercel vercel bot temporarily deployed to Preview February 3, 2022 05:36 Inactive
@vercel vercel bot temporarily deployed to Preview February 3, 2022 05:42 Inactive
@vercel vercel bot temporarily deployed to Preview February 3, 2022 05:53 Inactive
@vercel vercel bot temporarily deployed to Preview February 3, 2022 05:57 Inactive
@vercel vercel bot temporarily deployed to Preview February 3, 2022 23:45 Inactive
@vercel vercel bot temporarily deployed to Preview May 23, 2022 03:12 Inactive
@vercel vercel bot temporarily deployed to Preview May 23, 2022 03:25 Inactive
@vercel vercel bot temporarily deployed to Preview May 23, 2022 04:20 Inactive
@vercel vercel bot temporarily deployed to Preview May 23, 2022 23:50 Inactive
Noviny and others added 2 commits May 25, 2022 10:11
Co-authored-by: Josh Calder <josh@opensaas.com.au>
Co-authored-by: Daniel Cousens <413395+dcousens@users.noreply.github.com>
@vercel vercel bot temporarily deployed to Preview May 25, 2022 00:15 Inactive
@vercel vercel bot temporarily deployed to Preview May 26, 2022 02:22 Inactive
@vercel vercel bot temporarily deployed to Preview May 26, 2022 02:40 Inactive
@Noviny Noviny enabled auto-merge (squash) May 26, 2022 02:42
@Noviny Noviny merged commit ae81dc1 into main May 26, 2022
@Noviny Noviny deleted the s3-assets branch May 26, 2022 02:52
@boyboy1995
Copy link

boyboy1995 commented Jun 8, 2022

Hi, is this file config written in the right way to using s3 storage for file field? For some reasons all properties not being recognized in the storage object.
Screenshot 2022-06-08 at 16 18 03

Screenshot 2022-06-08 at 16 03 31

@Andrey-Bazhanov
Copy link

looks like this is not released yet... documentation is updated but @keystonejs/core - not

@dcousens dcousens changed the title Rewrite of Image and Files Rewrite of Image and Files (breaking) Jun 9, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants