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

Pages using shadow endpoints do not render until all data is loaded #4458

Closed
half-metal opened this issue Mar 27, 2022 · 6 comments
Closed

Comments

@half-metal
Copy link

Describe the bug

A page using (shadow) endpoints won't render until the data is returned. This is an issue in cases where for example a database call takes over 10 seconds, and to a user would appear to just be a site failing. This issue refers to using shadow endpoints as described in this solution #3532

I made an assumption I could merely use an #await block to display the data but the page will still not render anything until all data loaded for that particular component is returned even if other components are on the page. This may not be an issue if data being returned fast, but if you have a database call that takes > 10 seconds or multiple database calls, then the page will be in that load state until data is loaded. I describe how I made this work here #4456 and hopeful to use this, but soon came to realize this puts a wrench in database calls. While this design may have been to do just that, prevent any loading or flicker, I think an option to enable rendering before data is loaded would make this functionality more flexible.

Additionally, if you have multiple pages open, this cascades into each page waiting to load before it tries to run the query for the next page.

Perhaps there is a better way to do this that someone can point out, it's not clear to me from the Sveltekit docs.

Reproduction

The flow is the following: queryDatabase.js > data-result.js > data-result.svelte
First the js file which calls the database and receives data query-database.js

import oracledb from 'oracledb';
let result
try {
    oracledb.initOracleClient({libDir: 'C:\\oracle\\instant-client\\instantclient_21_3'});
  } catch (err) {
    console.error('Whoops!');
    console.error(err);
    //process.exit(1);
  }

oracledb.outFormat = oracledb.OUT_FORMAT_OBJECT;

const mypw = '**user removed**'
const myuser = '**pw removed**'

export default async function sendOracleResult() {

  let connection;

  try {
    connection = await oracledb.getConnection( {
      user          : myuser,
      password      : mypw,
      connectString : "**ip:port**/**service**"
    });

    result = await connection.execute(
      `SELECT *
       FROM schema_name.settings
       where param_name like '%field%'`,
    );
    console.log(result.rows);
  } catch (err) {
    console.error(err);
  } finally {
    if (connection) {
      try {
        await connection.close();
      } catch (err) {
        console.error(err);
      }
    }
  }
  return result
}

then the shadow endpoint data-result.js will return the body:

import queryDatabase from '$lib/queryDatabase.js'

export async function get() {
    let result = await queryDatabase()
    console.log('result is', result)
    return {
        body:{
            result: JSON.stringify(result),
            }
    };
}
get()

and finally the page that will not render anything until that data is retrieved which is the issue

<script> 
//this file will get data from shadow endpoint
		export let result
</script>

<div class="content">
	<p>{result}</p>
	<pre>this gives data above</pre>
</div>

Logs

No response

System Info

Sveltekit 1.0.0-next.303
Chrome Version 99.0.4844.84 (Official Build) (64-bit)
{
  "name": "db-viewer",
  "version": "0.0.1",
  "scripts": {
    "dev": "svelte-kit dev --port 4000",
    "build": "svelte-kit build ",
    "package": "svelte-kit package",
    "preview": "svelte-kit preview --port 4001",
    "prepare": "svelte-kit sync",
    "lint": "prettier --ignore-path .gitignore --check --plugin-search-dir=. . && eslint --ignore-path .gitignore .",
    "format": "prettier --ignore-path .gitignore --write --plugin-search-dir=. ."
  },
  "devDependencies": {
    "@sveltejs/adapter-auto": "next",
    "@sveltejs/kit": "next",
    "eslint": "^7.32.0",
    "eslint-config-prettier": "^8.3.0",
    "eslint-plugin-svelte3": "^3.2.1",
    "prettier": "^2.5.1",
    "prettier-plugin-svelte": "^2.5.0",
    "svelte": "^3.44.0"
  },
  "type": "module",
  "dependencies": {
    "dotenv": "^16.0.0",
    "oracledb": "^5.3.0",
    "pg": "^8.7.3"
  }
}

Severity

annoyance

Additional Information

No response

@Conduitry
Copy link
Member

This is functioning as intended. Anything in load (including anything from shadow/page endpoints) will be fully loaded before the page displays (whether this is being rendered on the server or on the client). If you want don't want certain pages to wait for certain data, you can load that data in an onMount callback on that page or something similar.

@half-metal
Copy link
Author

onMount works fine with most calls, but when importing 'oracledb' or 'pg', therein lies the problem I was hoping Shadow Endpoints would resolve, which it does except the delayed rendering of page. Let's say I use onMount and call the js file that successfully queries the database and returns the data, and then start Sveltekit up using npm run dev - when that page loads it will now give a Vite error about "process is not defined"

500
process is not defined
ReferenceError: process is not defined
at node_modules/oracledb/lib/util.js (http://localhost:4000/node_modules/.vite/oracledb.js?v=83edaa7e:101:66)
at __require2 (http://localhost:4000/node_modules/.vite/chunk-XWISVH4F.js?v=83edaa7e:16:50)
at node_modules/oracledb/lib/oracledb.js (http://localhost:4000/node_modules/.vite/oracledb.js?v=83edaa7e:1999:20)
at __require2 (http://localhost:4000/node_modules/.vite/chunk-XWISVH4F.js?v=83edaa7e:16:50)
at node_modules/oracledb/index.js (http://localhost:4000/node_modules/.vite/oracledb.js?v=83edaa7e:2265:22)
at __require2 (http://localhost:4000/node_modules/.vite/chunk-XWISVH4F.js?v=83edaa7e:16:50)
at http://localhost:4000/node_modules/.vite/oracledb.js?v=83edaa7e:2271:24

And below is a .svelte file which has some extraneous html to show what I've tried to have this data display with onMount. This .svelte file fails to get the data from the js file that works fine without sveltekit.

<script> 
import queryOracle from '../lib/queryOracle.js'
import { onMount } from 'svelte';
import queryOracleStore from '../stores/queryOracleStore'
import 'dotenv/config'

let result

export async function get() {
    result = await queryOracle()
    console.log('result is', result)
    return result
}

onMount(async() => {
    result = await queryDatabase()
    console.log('result is', result)
    return result
});

let entry = result
    </script>
    <div>this should display something while it's loading</div>
    <div>result is {result}</div>
    
{#await result}
	<p>...waiting</p>
{:then number}
	<p>The number is {result}</p>
{:catch error}
	<p style="color: red">{error.message}</p>
{/await}

There are dozens of pages on hacky workarounds related to this and Sveltekit that did not work for me. Just for example:
https://dev.to/richardbray/how-to-fix-the-referenceerror-global-is-not-defined-error-in-sveltekitvite-2i49
https://scottspence.com/posts/sveltekit-env-secrets
https://timdeschryver.dev/blog/environment-variables-with-sveltekit#the-problem

But I still get this error with sveltekit and oracledb. I can do npm run build and npm run preview and seems to not give that error, but then gives an error about package.json. Would prefer just seeing this work on npm run dev and doing database calls from Sveltekit. @Conduitry have you been able to do a database call to Oracle or Postgres from Sveltekit or have a clear example of how that is done? Maybe I am heading in the wrong direction, and this should be moved over to Discussion. I read the Vite FAQs and the Svelte FAQs on Vite but something seems to be missing.

I could also go back to just using Server to return the database query responses, but this would be much cooler to do something straight from Sveltekit.

@half-metal
Copy link
Author

I'll just create another page that will fetch from the Sveltekit endpoint page via const response = await fetch('oracle-result');, and append __.data.json to the endpoint so json data is returned. That means 4 files to display a database query in Sveltekit page, but at least allows the flexibility to load a page right away instead of waiting for query to complete at least.

@mrkishi
Copy link
Member

mrkishi commented Mar 28, 2022

You just need two files: a page and a standalone endpoint.

@half-metal
Copy link
Author

half-metal commented Mar 28, 2022

@mrkishi are you sure about that when doing database calls from Sveltekit? A page and a standalone works fine for API calls, but when attempting to use a module that connects to a db like oracledb or pg, Vite gives an error about process is not defined. You can do two pages, if you are fine that the page will wait to render until the data is loaded, but if you want to render the page that isn't just a browser loading until the query response is returned, then it seems you need at least 3 files for Sveltekit in your /routes folder. Maybe you can provide an example, because from what I encountered, a page and endpoint will either not render in your browser until all db data responses occur, or give a Vite error using npm run dev.

@half-metal
Copy link
Author

I see, I put a function in the .js file that connects, queries, and then returns the content in JSON, then a .svelte file with different name to fetch the data from that url since there is no other .svelte file with same name. Thanks, glad I figured that out.

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