Skip to content

Is it possible to isolate custom blocks from the rest of the SFC? #3761

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

Open
UfukUstali opened this issue Nov 29, 2023 · 1 comment
Open

Comments

@UfukUstali
Copy link

I am currently working on a PR for a nuxt module called server-block-nuxt by @Hebilicious which will get multiple server blocks inside of the SFC to work.

<server lang="ts">
import db from "db";

export const GET = defineEventHandler(() => {
//            ^? Cannot redeclare block-scoped variable 'GET'. ts(2451)
  return db.query("hello");
});
</server>

<server lang="ts">
export const GET = defineEventHandler(() => {
//            ^? Cannot redeclare block-scoped variable 'GET'. ts(2451)
  return { message: "world" };
});
</server>

<script lang="ts" setup>
const { data } = await useFetch("/api/about");
const GET = "GET";
//     ^? Cannot redeclare block-scoped variable 'GET'. ts(2451)
db.query("hello")
//^? does exist as a type but at runtime it isn't here
</script>

<template>
  <div>
    <p>{{ GET }}</p>
  </div>
</template>

But if you look at the above example I am faced with a typescript error and the error is not just limited to custom blocks because it appears just the same in script setup.

Another problem is if you look at the top server block we import db from "db" but this import is also made available inside of the script setup only as a type as the server blocks are removed by a vite plugins transform option during run/build-time

There is already a VueLanguagePlugin required to get auto-imports and types to work inside the custom blocks if the desired functionality can be achieved through a plugin it is also a possibility but I couldn't find any documentation on plugin authoring.

This is the current plugin.

import type { VueLanguagePlugin } from "@vue/language-core"

const plugin: VueLanguagePlugin = () => {
  return {
    name: "sfc-server-volar",
    version: 1,
    resolveEmbeddedFile(fileName, sfc, embeddedFile) {
      if (embeddedFile.fileName.replace(fileName, "").match(/^\.(js|ts|jsx|tsx)$/)) {
        for (const block of sfc.customBlocks) {
          const content = embeddedFile.content
          if (block.type === "server") {
            content.push([
              block.content, // text to add
              block.name, // source
              0, // content offset in source
              {
                // language capabilities to enable in this segment
                hover: true,
                references: true,
                definition: true,
                diagnostic: true,
                rename: true,
                completion: true,
                semanticTokens: true
              }
            ])
          }
        }
      }
    }
  }
}

export default plugin

My current plan is to manipulate the block.content inside of the plugin before pushing it to embededFile.content like so:

Given:

import db from "db";
export const GET = defineEventHandler(() => {
  return db.query("hello");
});
export const POST = defineEventHandler(() => {
  return db.query("goodbye");
});

Modified:

import db from "db"; // 2. hoist the imports out of the block
{ // 1. put the declarations inside of a block to isolate them
  const GET = defineEventHandler(() => {
// ^? 3. delete export string
    return db.query("hello");
  });
  const POST = defineEventHandler(() => {
// ^? 3. delete export string
    return db.query("goodbye");
  });
}

This wouldn't however solve the issue of imports of one block being also avalible inside of the others but just the "Cannot redeclare block-scoped variable 'GET'. ts(2451)". Which I am actually fine with since there is nothing sensitive being leaked, we only lose the type safety to some degree.

Conclusion:

If the above proposed solution is an acceptable one I will go through with it for the time being.

And I would like to request an official way of enabling/disabling this kind of behaviour inside of the plugin api to address the problems that could not be solved by simply manipulating the content. If there is one and I am not aware of it I would like to learn about it.

@UfukUstali UfukUstali changed the title Is it possible to isolate custom blocks? Is it possible to isolate custom blocks from the rest of the SFC? Nov 30, 2023
@davidmatter davidmatter added the question Further information is requested label Jul 7, 2024
@KazariEX KazariEX removed the question Further information is requested label Feb 21, 2025
@sonofmagic
Copy link

I am also looking for a similar solution at the moment, and I will continue to follow this closely.

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