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鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

Vue/Nuxt Documentation is confusing and incomplete #3182

Open
jbool24 opened this issue Apr 8, 2024 · 4 comments
Open

Vue/Nuxt Documentation is confusing and incomplete #3182

jbool24 opened this issue Apr 8, 2024 · 4 comments
Assignees

Comments

@jbool24
Copy link

jbool24 commented Apr 8, 2024

@samijaber @steve8708 PLEASE HELP 馃檹

I recently opened a support ticket via email but that did not result in sufficient resolution or a way forward. Is there any update on the stability of the SDK for Vue3/Nuxt3? This doesn't seem to work as expected. However I can't get a baseline because the Page model example is the only thing that worked as expected when following guides on https://www.builder.io/c/docs or https://www.builder.io/c/blueprints

There are a number of discrepancies between the examples that are spread all over the documentation and it is difficult to figure out what is most current. Here are some examples of conflicting information...

Examples in the Builder Editor for Vue/Nuxt

Nuxt seems to demonstrate using the older Vue2 sdk
320237890-124def76-9d2b-4d85-8322-d626f92ede7e

While Vue shows both Vue2 and Vue3 but doesn't provide context
320237905-a1a5e0d6-b5f3-4c08-829a-b8dbfa4d85cd

Examples for Section Type models following Announcement bar guide with Vue/Nuxt

  • does not mention of API Key (as above)
  • if API_KEY is part of runtime configs in nuxt.config.js
  • or if it needs to be on the Content component as props (also is this the same as RenderContent as mention above???)

320237925-bec7276e-b4fa-4614-93d6-8205d6d1217d

Nuxt3 general user exceptions are that a Nuxt Module uses configs in runtime for API-KEYs or app public configs for public keys which goes in the nuxt.config.js. This doesn't mention either method or where to init the module for usage with Section type only renderings.

320238490-345c3d2b-3a7f-4796-b48f-63d8212bd059

Editorial Example

This one shows both fetchOneEntry as well as using an API key on the component

  • 馃 Not sure why component needs the API key if we need to make async key call with fetch function.
  • There is no context or explanation so very difficult to understand

320239248-128361fe-28ac-44d1-afe3-b18734f55ce2


Main Questions:

  1. Do we use builder.init() or is that the old vue SDK and we should use @builder.io/sdk-vue instead and set an api-key prop on the component?
  2. If using component props is the correct method to init, why do we need a fetch function to call the data (that also has api-key as params? Is that not what the Content is doing with the api-key prop?
  3. Is there really a helper method getContent? Or is it fetchOneEntry? Or do we just use Fetch API and a rest endpoint?

I love what this project is aiming to do and because of its power I would like to use this with Vue/Nuxt often.
馃槏 But these example aren't concrete enough to understand and its a blocker to getting started.

I know there is a lot of busy work going on so I mentioned to Support and Partner Program reps that I would be willing to help clean up the docs and contribute back if I can get someone to explain the appropriate usage. Either way is it possible to close the gaps for Vue3 and Nuxt3 framework guides so they agree site-wide across the documentation and all examples? I really want to get using this but feeling frustrated at every step on-boarding myself.

Thanks 馃憤

@samijaber
Copy link
Contributor

@jbool24 Thanks for filing as a separate issue.

To answer your question: our Vue SDK is perfectly stable and reliable on Vue 3 (with or without Nuxt 3). It has hit v1.0 recently and we continue to improve it.

Thank you for pointing out some of the inconsistencies in our docs. They were relying on old syntax from our first generation Vue SDK which is no longer supported. We are actively going over our Vue documentation now to make sure all old examples are updated to match the Gen 2 Vue SDK.

Meanwhile, I encourage you to look at our example codebases which are up to date. You can see links to all of them here https://github.com/BuilderIO/builder/tree/main/packages/sdks/output/vue#usage

To answer your questions: builder.init() is the old way. Instead, you must use fetchOneEntry and provide the api-key prop to the component. The latter is needed for Symbols to dynamically fetch their content, which is sometimes needed.

@jbool24
Copy link
Author

jbool24 commented Apr 9, 2024

Thanks so much @samijaber!! 馃檹 鉂わ笍 I appreciate you looking into this.

Is it safe to assume the new doc updates will reflect more context about what [symbols need] to dynamically fetch their content is about? That sounds confusing still if the fetchOne is getting the content or is that an internal implementation that I should be digging into source code for? Or something lib users don't need to understand?
If it's the latter can I make a suggestion to allow environment variables be introduced to hide/remove this detail from the view of the user? It feels strange to have to supply it on the component.

Meanwhile, I encourage you to look at our example codebases which are up to date. You can see links to all of them here https://github.com/BuilderIO/builder/tree/main/packages/sdks/output/vue#usage

Thanks for directing me here! Didn't even know that existed. I was lookin'
馃憠 https://github.com/BuilderIO/builder/blob/main/examples/vue/nuxt-3
馃憠 and here https://github.com/BuilderIO/builder/tree/main/examples/vue/vue-3
and they only have Page model examples.

Thank for this support.

@samijaber
Copy link
Contributor

You do not need to worry about why the api-key is needed, or when it is used. THe SDK takes care of that.

We do have internal tickets tracking an issue on how to better explain the API key prop in <Content>.

For your information:
When fetching content with deeply nested symbols, it is possible that the nested symbol's content is not recursively fetched in the fetchOneContent (depending on whether you set the enrich flag to true or false, among other things). This is why we require the api-key prop to Content. If we encounter a scenario where the Symbol's content was not provided in the original JSON, we must perform additional requests to acquire the content.

Note that the API key is public: it is not a private key, and is therefore safe to consume and store on the client side.

@jbool24
Copy link
Author

jbool24 commented Apr 10, 2024

Thanks for clarification. I would still like to recommend that for use cases in the Nuxt community, using runtimeConfigs values for keys (public or not) is the recommended way to manage them. Also, if loading Builderio recommends using a module llike @builder.io/sdk-vue/nuxt like what is currently recommended to do hereLanding Pages Then a more Nuxt aligned uasge is to add keys to the module configs to allow the module to configure itself at build time via the internal module.ts and runtime scripts (such as plugins which would handle prop default options). These things get injected into the client code as well.

For full clarify here is an example of what the module and runtime plugin could do

// <module-root>/module.ts
import {
  defineNuxtModule,
  addPlugin,
  addComponentsDir,
  addImports,
  addImportsDir,
  createResolver
} from "@nuxt/kit";
import type { NuxtHookName } from "@nuxt/schema";

export interface ModuleOptions {
  publicApiKey: string,
  devtools: boolean, // enable nuxt/devtools integration
  apiOptions: any, // default options for fetchOneEntry
  customComponentsDir: string, // enable global directory for custom builder components
}

export default defineNuxtModule<ModuleOptions>({
  meta: {
    name: "@builder.io/sdk-vue/nuxt",
    configKey: "builderio"
  },
  defaults: {
    publicApiKey: '',
    devtools: false,
    customComponentsDir: '~/components/builderio',
    apiOptions: {},
  },
  setup(options, nuxt) {
    const resolver = createResolver(import.meta.url);

    if(nuxt.options.vite.optimizeDeps) {
      nuxt.options.vite.optimizeDeps.include = nuxt.options.vite.optimizeDeps.include || [];
      // anything to manually add to the bundle
      nuxt.options.vite.optimizeDeps.include.push("@builder.io/sdk-vue");

      nuxt.options.vite.optimizeDeps.exclude = nuxt.options.vite.optimizeDeps.exclude || [];
      // anything to exclude from the bundle
      nuxt.options.vite.optimizeDeps.include.push("@builder.io/sdk-vue");
    }


    // Enable dirs
    if(options.customComponentsDir) {
      addComponentsDir({ path: options.customComponentsDir, global: true, pathPrefix: false });
    }
    nuxt.options.build.transpile.push(resolver.resolve("./runtime"));
    nuxt.options.build.transpile.push("@builder.io/sdk-vue"); // <-- if we need/want to transpile

    // Add plugin
    nuxt.options.runtimeConfig.public.builderio = options;
    const enablePluginCondition = options.usePlugin === true && options.enableSudoMode === false;
    
    // here's magic sauce 馃獎 to pre-config the key a bundle time.
    // User doesn't need to care after setting ENV or directly in nuxt.config.ts
    if (enablePluginCondition) {
      addPlugin(resolver.resolve("./runtime/plugin")); // <-- see ./runtime/plugin.ts example below
    }

    // Add global CSS
    nuxt.options.css.push('@builder.io/sdk-vue/css');

    // Add auto imports globally
    const names = [
      "fetchEntries",
      "fetchOneEntry",
    ];
    for (const name of names) {
      addImports({ name, as: name, from: "@builder.io/sdk-vue" });
    }

    // Add composables if there are helpers
    addImportsDir(resolver.resolve("./runtime/composables"));

    // We could maybe embed the live Editor too 馃し if thats possible 
    if (options.devtools) {
      nuxt.hook('devtools:customTabs' as NuxtHookName, (iframeTabs: Array<unknown>): void => {
        iframeTabs.push({
          name: 'builderio',
          title: 'Builder.io',
          icon: 'i-logos-builderio-icon',
          view: {
            type: 'iframe',
            src: 'https://builder.io/content',
          }
        })
      })
    }
  }
});
// <module-root>/runtime/plugin.ts
import { Content as BuilderContent } from '@builder.io/sdk-vue';
import { defineNuxtPlugin, useRuntimeConfig } from "#app";

/**
 * Builder.io Pre-configuration from 
*
* This would be set in nuxt.config.ts
* builderio {
*   publicApiKey: string - could also be set by user with import.meta.env.NUXT_BUILDERIO_PUBLIC_API_KEY
*   devtools: boolean
*   apiOptions: any
*   customComponentsDir: string
* }
*/
export default defineNuxtPlugin(({ vueApp }) => {
  let { builderio } = useRuntimeConfig().public;
  builderio = JSON.parse(JSON.stringify(builderio));
  vueApp.use(BuilderContent, { ...builderio });
});

This would represent a much better DX for Nuxt users as this is what we are most accustomed to.

And with vanilla Vue thanks to Vite, its usually preferred to use import.meta.env for such values. At bundle time Vite will rewrite all ENV vars that are marked with VITE_ into the bundle. Nuxt also offers this method as well as another alternative to runtimeConfigs in nuxt.config.ts. Anything with NUXT_ is bundled to the client for browser-side use. This might be a better way to conceal the fact that API key is being used inside the component and one less prop for the user to be concerned about. Thanks again for this consideration. 馃憤 馃

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

3 participants