Skip to content

Allow Scripts That Only Run On the Server ("Micro" Endpoints For Routes) #3483

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

Closed
Acmion opened this issue Jan 21, 2022 · 5 comments
Closed

Comments

@Acmion
Copy link

Acmion commented Jan 21, 2022

Describe the problem

I am often building applications where the server file system is an integral aspect, but this also applies to anything that requires execution on the server, such as database calls. Thus I often have components or routes of the following format:

<script lang="ts">
    import fs from "fs"
    
    var entries = fs.readdirSync(".")
</script>

{#each entries as e}
    {e}<br>
{/each}

The component is SSR rendered just fine, but when the hydration kicks in things start to fail. The reason in this case is that client side code can not access fs. In old school MVC projects the example above is essentially the way similar things were handled.

Blazor Server, which is a relatively new web framework project by Microsoft, is great for use cases just like these. You just develop your components and routes without worrying about creating api endpoints.

Describe the proposed solution

I would like to somehow guarantee that certain code is only executed on the server. For example:

<script context="server">
     // Top level code would get executed every time

     import fs from "fs"

     var data = fs.readDirSync(".")
</script>

A better solution would probably be "micro" endpoints, which would be available for routes. This is actually a quite common approach in many MVC frameworks. For example:

<script context="endpoint">
    // This works almost as normal SvelteKit endpoints, but returning a response is not needed
    // Top level code would get executed every time and appropriate functions called depending on the request type

    import fs from "fs"

    var data = []

    export function get()
    {
        data = fs.readDirSync(".")
    }
</script>

Alternatives considered

Checking the environment does not really work, because you can not conditionally import modules.

import { browser} from '$app/env'

if(!browser)
{
    // Does not work, because imports need to be top level statements
    import fs from "fs"
}

Conditional dynamic imports could work, but they are somewhat of a hassle.

Disabling route hydration works in certain cases, but not generally.

Creating an api endpoint works fine, but then you get the overhead of first developing that endpoint and then creating an appropriate request to it. Because endpoints are not statically typed, this means that the developers must remember the correct url, the correct method and the correct payload. This is significantly harder to maintain than the proposed solutions.

Svemix is a vite plugin that essentially enables this behavior.

Importance

would make my life easier

Additional Information

The proposed solutions are probably easier to implement for routes than components. Additionally, not sure whether changing the context of a script is the appropriate solution.

@pixelmund
Copy link
Contributor

pixelmund commented Jan 21, 2022

You might want to check out svemix which solves basically what you described with a vite plugin.

@dodiameer
Copy link

I was just typing my comment about svemix when @pixelmund replied — I haven't used it yet but I have used Remix and the ideas of Remix were borrowed by svemix so I assume they function similarly and solve the issue you described

@Acmion
Copy link
Author

Acmion commented Jan 21, 2022

Awesome! Svemix seems just like the thing I need!

I'll add Svemix to the original issue under "Alternatives considered", but I'll leave the issue open, just in case this is every directly implemented in SvelteKit.

@Rich-Harris
Copy link
Member

We've considered this idea in the past and decided against it. You might be interested in #3532 though

@Acmion
Copy link
Author

Acmion commented Jan 28, 2022

Could something like <svelte:static>HTML HERE</svelte:static> be considered?

The <svelte:static> tags could be rendered only on the server and not in the client. Some treeshaking algorithm could be utilized to drop specific code from the client side.

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