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

allow directly embedding sanity studio with <SanityStudio> component #541

Open
danielroe opened this issue Oct 29, 2022 · 9 comments
Open

Comments

@danielroe
Copy link
Collaborator

No description provided.

@procrates
Copy link

procrates commented Dec 10, 2022

Any updates on this? Currently working on this using renderStudio function but getting:
Cannot read properties of undefined (reading 'REACT_APP_SC_ATTR')

I believe it is because vite using a different way to get env vars.

<script lang="ts" setup>
import { renderStudio, defineConfig } from "sanity";
import { deskTool } from "sanity/desk";

const nuxtConfig = useRuntimeConfig();
console.log("nuxtConfig", nuxtConfig);

const config = defineConfig({
  basePath: "/studio",
  plugins: [deskTool()],
  name: "Sanity Studio",
  projectId: nuxtConfig.public.sanity.projectId,
  dataset: nuxtConfig.public.sanity.dataset,
  schema: {
    types: [
      {
        type: "document",
        name: "post",
        title: "Post",
        fields: [
          {
            type: "string",
            name: "title",
            title: "Title",
          },
        ],
      },
    ],
  },
});

renderStudio(document.getElementById("app"), config);
</script>

<template>
  <div id="app"></div>
</template>

<style scoped></style>

@OlaAlsaker
Copy link
Contributor

OlaAlsaker commented Dec 12, 2022

I found a way to embed Sanity Studio 😄

I followed this tutorial by Sanity, and added some extra code/steps to make it work in Nuxt.

This should be a pretty complete tutorial on how to embed Sanity Studio v3 in Nuxt 3:

Step 1

Add Sanity to your project

npm install sanity@latest

Step 2

Create a new plugin in your plugins-folder called sanity-studio.client.ts with the following content:

import { defineConfig } from 'sanity';
import { deskTool } from 'sanity/desk';
import { schemaTypes } from '../schemas';

export default defineNuxtPlugin((nuxtApp) => {
  const config = defineConfig({
    plugins: [deskTool()],
    name: '<PROJECT-NAME>',
    projectId: '<PROJECT-ID>',
    basePath: '/admin', // Same as our page
    schema: {
      types: schemaTypes, // Your Sanity-schemas
    },
  });

  return {
    provide: {
      sanityConfig: config,
    },
  };
});

Step 3

I assume you I don't have to explain in detail how to define Sanity-schemas, but in my example I created a folder in the root of my project called schemas, and inside I have two files:

animal.ts

export default {
  name: 'animal',
  type: 'document',
  title: 'Animal',
  fields: [
    {
      name: 'name',
      type: 'string',
      title: 'Name',
    },
  ],
}

index.ts

import animal from './animal'

export const schemaTypes = [animal]

Step 4

In your pages-folder, create a new folder called admin. Under that folder, create a file called [...slug].vue. You will now have:

pages
- admin
-- [...slug.vue]

Add the following content to the page

<template>
  <div id="studio" ref="studio"></div>
</template>

<script setup>
import { renderStudio } from 'sanity';

const { $sanityConfig } = useNuxtApp();

const studio = ref();
onMounted(() => {
  renderStudio(studio.value, $sanityConfig);
});
</script>

<style>
/* This assumes no margin or padding on #app's parent(s) */
#studio {
  height: 100vh;
  max-height: 100dvh;
  overscroll-behavior: none;
  -webkit-font-smoothing: antialiased;
  overflow: auto;
}

/* Fix if you're using Tailwind.css */
*:not([data-ui='Popover__arrow']):not([data-ui='Tooltip__arrow']) > svg {
  display: inline;
}
</style>

Step 5

We also need to add some config to our nuxt.config.ts:

nuxt.config.ts

export default defineNuxtConfig({
  routeRules: {
    '/admin/**': {
      ssr: false,
    },
  },
  vite: {
    define: {
      // Fix broken process.env for styled-components in Sanity Studio
      'process.env': {
        REACT_APP_SC_ATTR: 'data-styled',
      },
    },
  },
});

Some explanation

routeRules - Sanity Studio does not support SSR, so we disable it for the admin-page we created.

vite - Sanity Studio is built on React and uses the styled-components package. It tries to access a propert in process.env, which does not exist, and therefore result in an exception. But with this config, we are able to work around the issue. Got the solution from nuxt/nuxt#13264.

Done! 🎉

Sanity Studio should now be running on /admin. Remember to add localhost to Sanity's CORS settings.

I have not tested this implementation fully as I just got it working myself, but it seems to be working fine.

@danielroe Would it be interesting to add this as a built-in option in the @nuxtjs/sanity module? Or at least add this tutorial to the documentation? Let me know what you think, and I will happily submit a PR 😄

Edit/note

It seems like you will run in to some issues if you try to customize Sanity Studio with React-components. For instance, if you want to change the logo, you have to create a React-component with JSX. But with my solution it will give the following error:

Error: Objects are not valid as a React child (found: object with keys {__v_isVNode, __v_skip, type, props, key, ref, scopeId, slotScopeIds, children, component, suspense, ssContent, ssFallback, dirs, transition, el, anchor, target, targetAnchor, staticCount, shapeFlag, patchFlag, dynamicProps, dynamicChildren, appContext, ctx}). If you meant to render a collection of children, use an array instead.
Error: Objects are not valid as a React child (found: object with keys {__v_isVNode, __v_skip, type, props, key, ref, scopeId, slotScopeIds, children, component, suspense, ssContent, ssFallback, dirs, transition, el, anchor, target, targetAnchor, staticCount, shapeFlag, patchFlag, dynamicProps, dynamicChildren, appContext, ctx}). If you meant to render a collection of children, use an array instead.
    at throwOnInvalidObjectType (http://localhost:3000/_nuxt/node_modules/.vite/deps/chunk-XHZEAB7L.js?v=23f3e8d7:20784:17)
    at reconcileChildFibers2 (http://localhost:3000/_nuxt/node_modules/.vite/deps/chunk-XHZEAB7L.js?v=23f3e8d7:21403:15)
    at reconcileChildren (http://localhost:3000/_nuxt/node_modules/.vite/deps/chunk-XHZEAB7L.js?v=23f3e8d7:23815:37)
    at mountIndeterminateComponent (http://localhost:3000/_nuxt/node_modules/.vite/deps/chunk-XHZEAB7L.js?v=23f3e8d7:24490:13)
    at beginWork (http://localhost:3000/_nuxt/node_modules/.vite/deps/chunk-XHZEAB7L.js?v=23f3e8d7:25389:22)
    at beginWork$1 (http://localhost:3000/_nuxt/node_modules/.vite/deps/chunk-XHZEAB7L.js?v=23f3e8d7:29190:22)
    at performUnitOfWork (http://localhost:3000/_nuxt/node_modules/.vite/deps/chunk-XHZEAB7L.js?v=23f3e8d7:28635:20)
    at workLoopSync (http://localhost:3000/_nuxt/node_modules/.vite/deps/chunk-XHZEAB7L.js?v=23f3e8d7:28574:13)
    at renderRootSync (http://localhost:3000/_nuxt/node_modules/.vite/deps/chunk-XHZEAB7L.js?v=23f3e8d7:28553:15)
    at recoverFromConcurrentError (http://localhost:3000/_nuxt/node_modules/.vite/deps/chunk-XHZEAB7L.js?v=23f3e8d7:28175:28)

So maybe the best solution is to keep the Sanity Studio completely outside of the Nuxt rendering. I guess one solution could be to just have an API-route in the server-folder that would return a plain static .html file that could render the studio.

Another solution would be to use Sanity CLI and build the studio project to static files, and put them in the static-folder or something, but I don't think that sounds like a smooth option.

Any thoughts on this, @danielroe ? 😇

@procrates
Copy link

Thank you so much Ola! Great work!

Copy link
Collaborator Author

This is great work! 🙌

I think the objectives are:

  1. bundle-split sanity deps so they aren't included in rest of nuxt app (or seamlessly handle as multi-frontend). I'd prefer it if it could be possible to include it in the same build.
  2. allow using custom react components within studio

I'm up for some different approaches to achieving these objectives, or even exposing multiple options for the end user.

@procrates
Copy link

@OlaAlsaker Do you know how to exclude types coming from the sanity studio? I am getting all these annoying react ts errors. I tried everything i found on google, and one solution working on fullcalendar but not for sanity,

@OlaAlsaker
Copy link
Contributor

Not yet, unfortunately! If you need to do custom things with React in Sanity, the best current solution is to have Sanity Studio as it's own project in a custom folder.

@procrates
Copy link

@OlaAlsaker I am thinking in combination with Nuxt. Sanity is enabled with ts and nuxt also. They are in the same repo (seperate folders).

@procrates
Copy link

Hello:) Any updates on this? I am heavily using sanity with Nuxt 3, and to be frank I think this would be such a good feature to implement for various reasons. I would love to help on this, but i dont know where to start. Maybe someone could point me in the right direction?

So the main stopper for me is the ability to create custom components in the studio, maybe this could even be done as a Vue component? And that react types flows into Nuxt types to make it useless.

Any ideas about a possible approach to this?
Thanks:D

@blowsie
Copy link

blowsie commented Feb 22, 2024

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

No branches or pull requests

4 participants