Skip to content
This repository has been archived by the owner on Mar 26, 2024. It is now read-only.

Error: Cannot find module 'part:@sanity/base/client' when using Orderable Document List #265

Open
lotarbo opened this issue Apr 21, 2022 · 4 comments

Comments

@lotarbo
Copy link

lotarbo commented Apr 21, 2022

same error here sanity-io/orderable-document-list#14

@fevernova90
Copy link

fevernova90 commented Jun 29, 2022

Same type of error but with Error: Cannot find module 'part:@sanity/base/user.

Using a custom React component in sanity that imports import { FormField } from "@sanity/base/components"; and some other existing sanity internal library components.

sanity build compiles and prod site runs perfectly, just sanity-codegen throwing this error.

@mfanuzzi
Copy link

mfanuzzi commented Sep 13, 2022

This is a complex issue that has to do with babel resolution of sanity parts as its core.

For some custom components, this may be sufficient: #59 (comment)

But for Orderable Document List it isn't, as the type is defined via a function, eg orderRankField({ type: 'project' }),

Not sure what the solution actually is, but it may not really be possible with how sanity-codegen presently works.

@mfanuzzi
Copy link

mfanuzzi commented Sep 13, 2022

Here is a solution for this plugin specifically, though it may be helpful for other plugins as well.

There are two steps: first, extend the codegen babel config to "no-op" the target plugin. Second, mock the essential bits that you're expecting the function/plugin to return.

sanity-codegen.config.ts (taken from here):

import { defaultBabelOptions } from 'sanity-codegen/cli';
import { SanityCodegenConfig } from 'sanity-codegen';

const config: SanityCodegenConfig = {
  schemaPath: './schemas/index',
  outputPath: '../web/src/config/sanity-schema.ts',

  babelOptions: {
    ...defaultBabelOptions,
    plugins: [
      ...defaultBabelOptions.plugins.filter(
        ([key]) => key !== 'module-resolver',
      ),
      [
        'module-resolver',
        {
          root: ['.'],
          alias: {
            // The below are all the defaults
            'part:@sanity/base/schema-creator':
              'sanity-codegen/schema-creator-shim',
            'all:part:@sanity/base/schema-type':
              'sanity-codegen/schema-type-shim',
            'part:@sanity/base/schema-type': 'sanity-codegen/schema-type-shim',
            '^part:.*': 'sanity-codegen/no-op',
            '^config:.*': 'sanity-codegen/no-op',
            '^all:part:.*': 'sanity-codegen/no-op',

            // Here we specify which plugins need to be mocked
            // (see mocks.ts for more info)
            // 👇👇👇
            '@sanity/orderable-document-list/lib/helpers/constants':
              'sanity-codegen/no-op',
            '@sanity/orderable-document-list': 'sanity-codegen/no-op',
            // 👆👆👆
          },
        },
      ],
    ],
  },
};

export default config;

I created a mocks.ts to store my mock of orderRankField() (and others in the future) like so:

import { orderRankField as _orderRankField } from '@sanity/orderable-document-list';
const constants = require('@sanity/orderable-document-list/lib/helpers/constants');

/** a mock of orderRankField for typegen purposes */
export const orderRankField = (props: {
  type: string;
  title?: string;
  icon?: any;
  id?: string;
  filter?: string;
  params?: {
    lang: 'en_US';
  };
}) => {
  const name =
    typeof constants.ORDER_FIELD_NAME === 'string'
      ? constants.ORDER_FIELD_NAME
      : 'orderRank';

  const orf = {
    title: 'Order Rank',
    readOnly: true,
    hidden: true,
    name,
    type: 'string',
    ..._orderRankField(props),
  };

  return orf;
};

...so that I could then reference it in my document files, for example a "project" schema in project.ts:

import { orderRankField } from '../util'; // my mocked one, NOT the version from the plugin

export const projectDoc = {
  name: 'project',
  type: 'document',
  title: 'Project',
  fields: [
    name,
    orderRankField({ type: 'project', title: 'Projects' }),
  ],
} as const;

@alexrohleder
Copy link

A solution that worked for me is to use babel-plugin-search-and-replace to replace the custom input imports with a dummy component. Inspired by this solution: #59 (comment)

import { SanityCodegenConfig } from "sanity-codegen"
import { defaultBabelOptions } from "sanity-codegen/cli"

const sanityCodegenConfig: SanityCodegenConfig = {
  schemaPath: "./schemas/schema",
  outputPath: "./schema.ts",

  babelOptions: {
    ...defaultBabelOptions,
    plugins: [
      ...defaultBabelOptions.plugins,
      [
        "search-and-replace",
        {
          rules: [
            {
              search: /src\/components\/.*/, // part of the path to your components
              replace: "sanity-codegen-components.tsx", // a file at the same level of your search
            },
          ],
        },
      ],
    ],
  },
}

export default sanityCodegenConfig

We could possibly refactor this to make use of sanity-codegen/no-op instead of creating a dummy component.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants