Skip to content

maoberlehner/storyblok-migrate

Repository files navigation

storyblok-migrate

Patreon Donate Build Status GitHub stars

Storyblok component and content migrations.

ko-fi

Warning: this project is at a very early stage. Due to the nature of what this package does, it has the potential to destroy all your content. It is strongly recommended that you backup your Storyblok Space before use. Use at your own risk.

Usage

storyblok-migrate can be used either as a global or as a locally installed CLI tool or it can also be used programmatically. But it is recommended to use it as a local dependency of your project.

# Install it as a local dependency of your project.
npm install storyblok-migrate

In the following example you can see a typical file tree of a Storyblok website project. However, you can see that we have added an additional storyblok folder. This is the default directory where storyblok-migrate looks for component definition files. You can change the directory via a configuration setting.

your-storyblok-project/
├── ...
├── assets/
├── src/
├── storyblok
│   ├── article.js
│   └── meta_image.js
└── ...

Component definitions

Next up you can see how to structure component definitions. You can read more about how to structure the schema part of the definition file and all the possible field types in the official Storyblok API documentation.

The migrations property is an optional array with functions you want to run on every migration. It is recommended to either add a condition to prevent a migration from running a second time after it has already done its job, or remove it completely when it is no longer needed. However, for documentation purposes, it is recommended to keep old migrations, but add a condition at the beginning to prevent them from running.

// storyblok/article.js
const metaImage = require('./meta_image');

module.exports = {
  display_name: 'Article',
  is_nestable: false,
  is_root: true,
  migrations: [
    // Replace `headline` field with new `title` field.
    ({ content }) => {
      if (!content.headline) return;

      content.title = content.headline;
      delete content.headline;
    },
  ],
  name: 'article',
  schema: {
    title: {
      pos: 0,
      type: 'text',
    },
    image: {
      component_whitelist: [metaImage.name],
      maximum: 1,
      pos: 10,
      restrict_components: true,
      type: 'bloks',
    },
  },
};
// storyblok/meta_image.js
module.exports = {
  display_name: 'Image',
  is_nestable: true,
  is_root: false,
  migrations: [
    // Replace `url` field with new `src` field.
    ({ content }) => {
      if (!content.url) return;

      content.src = content.url;
      delete content.url;
    },
  ],
  name: 'meta_image',
  schema: {
    src: {
      maximum: 1,
      pos: 0,
      type: 'image',
    },
    alt: {
      pos: 10,
      type: 'text',
    },
  },
};

Using the CLI

storyblok-migrate is a CLI tool with two modes. You can run it either in UI mode or with parameters.

Run in UI mode

When running storyblok-migrate in UI mode you'll be asked what migrations you want to run.

npx storyblok-migrate

Run with parameters

Usually you want to run storyblok-migrate with paramters as part of your build process because it's not possible to use the UI mode there.

{
  "scripts": {
    "migrate": "storyblok-migrate --content-migrations",
    "build": "npm run migrate && webpack"
  }
}

You can also run storyblok-migrate manually with parameters.

# Run all component migrations.
npx storyblok-migrate --component-migrations
# Run component migrations only for specific components.
npx storyblok-migrate --component-migrations --components article,meta_image
# Using shortcuts.
npx storyblok-migrate -p -c article,meta_image
# Run all content migrations.
npx storyblok-migrate --content-migrations
# Run content migrations only for specific content types.
npx storyblok-migrate --content-migrations --content-types article,product
# Using shortcuts.
npx storyblok-migrate -n -t article,product

Helpers

This package also provides some helper commands for your convenience.

Backup

In order to create a backup of your stories and components, you can use the following commands.

# Backup all components.
npx storyblok-backup --components
# Backup all stories.
npx storyblok-backup --stories
# Backup everything.
npx storyblok-backup --components --stories

You can change the location where backups should be saved by changing the backupDirectory configuration option.

Restore

You can also use the storyblok-backup-restore command to restore previously created backups.

# Restore components from a backup.
npx storyblok-backup-restore backup/components_2019-04-19T032721.json
# Restore stories from a backup.
npx storyblok-backup-restore backup/stories_2019-04-19T032721_1.json

Component export

If you want to export your components from Storyblok in order to use them as a starting point for your component definitions, you can use the storyblok-component-export CLI command.

# Export all components.
npx storyblok-component-export
# Export only specific components.
npx storyblok-component-export article,product

Running those commands creates new files for those components inside of your componentDirectory. If a component with the same name already exists, it will be overwritten!

Configuration

This is the default configuration. You must not check in your oauthToken into version control (especially if the repository is public)! Use environment variables instead.

// storyblok.config.js
module.exports = {
  backupDirectory: 'backup',
  componentDirectory: 'storyblok',
  dryRun: process.argv.includes('--dry-run'),
  oauthToken: process.env.STORYBLOK_OAUTH_TOKEN,
  spaceId: process.env.STORYBLOK_SPACE_ID,
};

Tips & Tricks

Fragments

You can add files starting with an underscore to your componentDirectory, those files will be ignored and not treated as component definition files. You can use those files to sepcify schema fragments which you can reuse in multiple component definition files.

// storyblok/_meta_image.js
module.exports = ({ startPos = 0 }) => ({
  image: {
    type: 'section',
    keys: [
      'image_src',
      'image_dominant_color',
      'image_alt',
      'image_title',
    ],
    pos: startPos,
  },
  image_src: {
    type: 'image',
    pos: startPos + 1,
  },
  image_alt: {
    type: 'text',
    pos: startPos + 2,
  },
  image_title: {
    type: 'text',
    pos: startPos + 3,
  },
});
// storyblok/article.js
const metaImageFragment = require('./_meta_image');

module.exports = {
  // ...
  schema: {
    title: {
      pos: 0,
      type: 'text',
    },
    ...metaImageFragment({ startPos: 10 }),
  },
  // ...
};

Roadmap

1.0.0

  • Migration versioning
  • Rollbacks
  • Import content from third party sources

About

Author

Markus Oberlehner
Website: https://markus.oberlehner.net
Twitter: https://twitter.com/MaOberlehner
PayPal.me: https://paypal.me/maoberlehner
Patreon: https://www.patreon.com/maoberlehner

License

MIT

About

Storyblok schema migrations

Resources

License

Code of conduct

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published