Collections loaded server + clientside

default discord avatar
zaunermax2 years ago
1 1

Hello,

we use Algolia to index some of the collection items in payload and our problem is, that the algolia indices are used in some collection hooks. As it turns out, payload uses the config file client AND serverside.

To create/edit/update algolia indices, you need to provide an admin key, which obviously should only be provided serverside. Though payload seems to load the exact same config file clientside as well, which then throws an error as the admin api key only exists serverside.

The problem arises as the indices are imported to the collections (which init algolia on import) and due to the fact that all collections are imported to the payload config file as well makes it so payload tries to init algolia clientside as well.

Is there any workaround for stuff in hooks, that have to be serverside only? I hope my explanation of the problem was sufficient, otherwise hit me up - thanks in advance 🙌

  • Selected Answer
    discord user avatar
    jmikrut
    2 years ago

    Hey @zaunermax!

    Great question. We have run into this exact issue in the past. The good news is that there is a super easy solution!

    You need to manually prevent Webpack from including your server-only code.

    In keeping to Payload's goal of sticking as close to JavaScript as possible, we just expose the Webpack config to you where you can utilize the variety of ways that Webpack allows you to do this.

    As Hooks are only executed server-side, we've commonly used Webpack's alias feature to swap out our Hooks with empty modules. Here is an example of a config that does exactly this:

    import path from 'path';
    import { buildConfig } from 'payload/config';
    import Customers from './collections/Customers';
    import Licenses from './collections/Licenses';
    
    const mockModulePath = path.resolve(__dirname, './mocks/emptyModule.js');
    
    export default buildConfig({
      admin: {
        webpack: (config) => ({
          ...config,
          resolve: {
            ...config.resolve,
            alias: [
              'fs',
              path.resolve(__dirname, './collections/Customers/generateForgotPasswordEmail'),
              path.resolve(__dirname, './collections/Customers/generateVerificationEmail'),
              path.resolve(__dirname, './collections/Customers/stripe/syncCustomer'),
              path.resolve(__dirname, './collections/Customers/stripe/updateCustomer'),
              path.resolve(__dirname, './collections/Licenses/stripe/createSubscription'),
              path.resolve(__dirname, './collections/Licenses/stripe/changePlan'),
            ].reduce((alias, path) => ({
              ...alias,
              [path]: mockModulePath,
            }), config.resolve.alias)
          }
        })
      },
      collections: [
        Customers,
        Licenses,
      ],
      serverURL: process.env.PAYLOAD_PUBLIC_SERVER_URL,
    });

    And then the ./mocks/emptyModule.js file just looks like this:

    module.exports = {};

    Take a look at the Webpack documentation for more info:

    https://payloadcms.com/docs/admin/webpack

    Does this help you out at all?

    3 replies
  • default discord avatar
    zaunermax2 years ago

    Thanks for the very elaborate answer, I'm going to try this right away 🙌

  • default discord avatar
    zaunermax2 years ago

    While this solution seems a bit hacky it works haha 😄 Thanks for your help! 🙌

  • discord user avatar
    DanRibbens
    2 years ago

    We considered other options such as having a whitelist or blacklist in the config, but this method ended up winning out. If you think of an alternate solution we'd like to hear it.

Star on GitHub

Star

Chat on Discord

Discord

online

Can't find what you're looking for?

Get help straight from the Payload team with an Enterprise License.