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

Inconsistent Component IDs Across Environments When Syncing Single Types #131

Closed
FrancoLab opened this issue Aug 5, 2024 · 13 comments
Closed
Labels
bug Something isn't working Needs investigation Further information is requested

Comments

@FrancoLab
Copy link

Description

We're encountering an issue when using the config-sync plugin to synchronise Single Types that heavily rely on components. While the initial sync works as expected, subsequent imports to different environments (e.g., production) face problems due to mismatched component IDs.

When syncing initially, the production system generates its own IDs, which then causes a mismatch in subsequent imports. This puts us in a situation where we need to remove all content and reimport for the sync to be successful. This workflow is not ideal for maintaining consistent data across environments.

Steps to Reproduce

  1. Set up a Single Type with nested components in Strapi
  2. Configure config-sync to include the Single Type and its components
  3. Perform an initial export and import (works correctly)
  4. Make changes to the Single Type in the source environment
  5. Export the changes and attempt to import them into a different environment

Behavior

The import fails or produces unexpected results due to mismatched component IDs between environments.

Configuration Example

{
  configName: "example-single-type",
  queryString: "api::example-single-type.example-single-type",
  uid: ["slug"],
  components: [
    "parentComponent",
    "parentComponent.childComponentA",
    "parentComponent.childComponentB",
    // ... other components
  ],
}
@fardarter
Copy link

I'm also having this issue. With the top level content-types the advice is to set a UUID rather than an incremented ID. What's the correct approach for components?

@boazpoolman boazpoolman added bug Something isn't working Needs investigation Further information is requested labels Aug 5, 2024
@boazpoolman
Copy link
Member

Hi @FrancoLab and @fardarter,

Thank you for reporting this issue.

I'm also having this issue. With the top level content-types the advice is to set a UUID rather than an incremented ID. What's the correct approach for components?

The components don't need a UUID because they can't exist without their parent content-type. So the UUID of the content-type should be enough uniquely identify them.

The import fails or produces unexpected results due to mismatched component IDs between environments.

I'm unable to reproduce this issue. My export/import works fine.
I've setup some components in the playground of the repo, see this draft PR.

Am I missing something?

@FrancoLab
Copy link
Author

Hey @boazpoolman

Thanks for the response. I can provide some additional information to help clarify if I'm configuring something incorrectly.

My config:

"config-sync": {
  enabled: true,
  config: {
    syncDir: "config/sync/",
    minify: false,
    soft: false,
    importOnBootstrap: true,
    excludedTypes: [],
  }
}

The JSON export results in:

{
  "slug": "example-single-type",
  "publishedAt": "2023-11-15T08:32:45.123Z",
  "parentComponent": {
    "id": 37,
    "childComponentA": {
      "id": 3,
      "body": [
        {
          "type": "paragraph",
          "children": [
            {
              "text": "Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae.",
              "type": "text"
            }
          ]
        }
      ]
    },
    "childComponentB": {
      "id": 2,
      "title": "Quis Nos?",
      "textIsGhost": true
    }
  }
}

The issue I'm facing relates to components being used across multiple sections. Because a component has an "id": 37, it creates a conflict. It appears that this specific ID is not used during sync, and the database generates its own. Consequently, when we sync a second time, we encounter conflicting IDs in the database where the ID in production doesn't match the ID in development.

Does this explanation help clarify the situation?

@fardarter
Copy link

@boazpoolman Thanks for this. What we're also finding with similar setup is that the export of the content-types which have components attached have IDs and then when they get synced twice the components lose the content and it can't be force imported.

@boazpoolman
Copy link
Member

@fardarter @FrancoLab I'm trying to pin-point if you both are experiencing the same issue. From the sounds of it your are.

@FrancoLab You said:

The issue I'm facing relates to components being used across multiple sections.

As far as I know a single component can't be used across multiple sections. That's also what distinguishes a component from a full blown relation. A component is bound to it's parent content entry, is created from within that content entry, and can't be used anywhere else.

It appears that this specific ID is not used during sync

This is true. While I was testing the components sync feature I remember whenever a component is imported using Config Sync it would re-create the component entirely. Giving it a new ID and everything. Though I didn't see that as an issue at the time because I figured components are only used within that one content entry, so re-creating wouldn't matter.

Do you think removing the id from the components config file would fix this issue?

@fardarter
Copy link

fardarter commented Aug 7, 2024

As far as I know a single component can't be used across multiple sections. That's also what distinguishes a component from a full blown relation. A component is bound to it's parent content entry, is created from within that content entry, and can't be used anywhere else.

@boazpoolman This is very useful architectural information. Do you have any supporting documentation from Strapi about intended use? It's possible we've approached this in the wrong way.

I'm not the person building out our content-types -- I'm doing the ops side, so I might need it spelled out gently for me. How would you create a reusable composable structure for reuse across multiple contexts? Eg, a hero banner where there is an image field and a text field and say three or four of the page types want to reuse that structure? The view taken by our FE team was that one sets up a component definition that gets instantiated in multiple places with specific content.

At least I hope I'm relaying it accurately.

This is true. While I was testing the components sync feature I remember whenever a component is imported using Config Sync it would re-create the component entirely. Giving it a new ID and everything. Though I didn't see that as an issue at the time because I figured components are only used within that one content entry, so re-creating wouldn't matter.

Do you think removing the id from the components config file would fix this issue?

I don't know enough about the Strapi internals to know if this would solve things. For things like repeatable entries, how would the sync know which item in the index to update?

That said, if you have a patch (we can use https://www.npmjs.com/package/patch-package) we can test out I'm very happy to try it. We've got a pretty well automated setup so it's not a large overhead. If it's not a simplish fix I'd also be happy (critically, though, with some guidance) to see if I can do the work and PR it in.

At the most basic level, hoping for the import to be idempotent.

Really appreciate the attention you're giving this!

@FrancoLab
Copy link
Author

Hey @boazpoolman.

Thank you for all this useful information. I really appreciate you looking into this.
Let me clarify a few more things. Below is a screenshot of one of our Single Types, accompanied by its config and exported data. I have also included a screenshot of the config sync interface from Strapi after the initial sync.

Strapi Single Type:
Screenshot 2024-08-08 at 06 20 55

Config Sync Interface:
Screenshot 2024-08-08 at 06 23 10

plugins.ts

{
configName: "about-us-page",
queryString: "api::about-us-page.about-us-page",
uid: ["slug"],
components: [
    "heroSection",
    "whoAreWe",
    "whoAreWe.sectionTitle",
    "whoAreWe.sectionBody",
    "ourValues",
    "ourValues.sectionTitle",
    "ourValues.iconCards",
    "softwareSolutions",
    "softwareSolutions.sectionTitle",
    "softwareSolutions.sectionBody",
    "softwareSolutions.sofwareSolutionCards",
    "softwareSolutions.softwareSolutionCards.link",
    "ourVision",
    "ourVision.sectionTitle",
     "ourVision.sectionBody",
    ],
},

JSON Output:

{
  "slug": "about-us-page",
  "publishedAt": "2024-07-31T10:57:12.844Z",
  "heroSection": {
    "id": 19,
    "title": "Elit labore elit minim aute non aute ex.",
    "description": "Elit labore elit minim aute non aute ex."
  },
  "whoAreWe": {
    "id": 25,
    "sectionBody": {
      "id": 1,
      "body": [
        {
          "type": "paragraph",
          "children": [
            {
              "text": "Elit labore elit minim aute non aute ex.",
              "type": "text"
            }
          ]
        }
      ],
      "textIsGhost": false
    },
    "sectionTitle": {
      "id": 1,
      "title": "Who Are We?",
      "textIsGhost": false
    }
  },

I hope this helps. In the meantime, I will attempt to remove the IDs and observe the effects on the sync and import processes.

@fardarter
Copy link

@FrancoLab Thanks for this! This is exactly how it looks to us as well!

@boazpoolman We tried removing the IDs for one of the files and the content data sync now appears to work, so this does seem to cut to the heart of the issue. However, we now have IDs appearing in the diff that are not present in the file, meaning the diff is noisy.

Another worry (which I guess we can check when I can get a minute -- if I get to it before you do I'll update) is that at each import the ID is now changed (as reflected in the diff). Given that it seems to be an incremental ID, are we duplicating data in the database?

@boazpoolman
Copy link
Member

boazpoolman commented Aug 8, 2024

Thanks @FrancoLab and @fardarter for clarifying

It seems as though the issue can be resolved by removing the id from the config files.
I've done so in the PR (#132) I've mentioned before. Could you test out if that resolves your issue?

You can simply install the PR in to your node_modules like so:

yarn add pluginpal/strapi-plugin-config-sync#pull/132/head
// or
npm install pluginpal/strapi-plugin-config-sync#pull/132/head

@FrancoLab
Copy link
Author

Awesome thanks @boazpoolman.

Going to have a look at this today and will get back to you ASAP.

Again, thank you for all the help on this.

@fardarter
Copy link

@boazpoolman This works for me as far as I can tell. If we're happy with it, will it be merged in or do we need to patch for now?

@FrancoLab
Copy link
Author

@boazpoolman - Also worked for me 🧘

@boazpoolman
Copy link
Member

Thanks for testing!
I've published a new version to NPM, v1.2.6.

Please consider supporting me through Github Sponsors.
It will allow me to keep maintaining Config Sync and other Strapi plugins.

https://github.com/sponsors/boazpoolman

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working Needs investigation Further information is requested
Projects
None yet
Development

No branches or pull requests

3 participants