Code Monkey home page Code Monkey logo

sveltekit-search-params's Introduction

sveltekit-search-params

The fastest way to read AND WRITE from query search params in sveltekit.

Warning

This package is meant to be used with Svelte-Kit as the name suggest. Because it uses api that are only present in Svelte-Kit it will not work in your normal svelte project.

MIT License

npm

npm

GitHub last commit

Contributing

Contributions are always welcome!

For the moment there's no code of conduct neither a contributing guideline but if you found a problem or have an idea feel free to open an issue

If you want the fastest way to open a PR try out Codeflow

Open in Codeflow

Authors

Installation

Install sveltekit-search-params with npm

  npm install sveltekit-search-params@latest -D

Usage/Examples

Simple case (single parameter)

The simplest and most effective way to use this library is by importing the method queryParam. You can invoke this method with a string that represent the search parameters you are looking for in the URL.

<script lang="ts">
	import { queryParam } from 'sveltekit-search-params';

	const username = queryParam('username');
</script>

Your username is {$username}

the function returns a store so make sure to use it with the $ prepended to handle auto-subscriprion. In case there's not a query parameter with the chosen name it will simply be null.

Writing to the store (single parameter)

Reading query parameters is cool but you know what is even cooler? Writing query parameters! With this library you can treat your store just like normal state in svelte. To update the state and conseguentely the url you can just do this

<script lang="ts">
	import { queryParam } from 'sveltekit-search-params';

	const username = queryParam('username');
</script>

Your username is {$username}
<input bind:value={$username} />

or if you prefer

<script lang="ts">
	import { queryParam } from 'sveltekit-search-params';

	const username = queryParam('username');
</script>

Your username is {$username}
<input
	value={$username}
	on:input={(e) => {
		$username = e.target.value;
	}}
/>

Encoding and decoding

By default query parameters are strings but more often than not tho we are not working with strings. We are dealing with numbers, boolean, arrays and complex abjects. During the creation of the store you can specify an object containing an encode and a decode property that will be used to transform your data from and to the type you need.

<script lang="ts">
	import { queryParam } from 'sveltekit-search-params';

	const count = queryParam('count', {
		encode: (value: number) => value.toString(),
		decode: (value: string | null) => (value ? parseInt(value) : null),
	});
</script>

The count is {$count}
<input bind:value={$count} type="number" />

this time $count would be of type number and the deconding function it's what's used to update the url when you write to the store.

Default values

Sometimes when we want to create a new variable we like to pass a default value. You can do this by passing a third field, defaultValue, in the second argument of the query param object.

<script lang="ts">
	import { queryParam } from 'sveltekit-search-params';

	const count = queryParam('count', {
		encode: (value: number) => value.toString(),
		decode: (value: string | null) => (value ? parseInt(value) : null),
		defaultValue: 10,
	});
</script>

The count is {$count}
<input bind:value={$count} type="number" />

this will make the query parameter change as soon as the page is rendered on the browser (the query parameter will change only if it's not already present and only the first time the application render).

Warning

You can't run goto on the server so if the page is server side rendered it will still have the null value (this is to say don't relay on the assumption that the store will always be not null).

Helpers encodings and decodings

Write an encode and decode function may seem trivial but it's tedious for sure. sveltekit-search-params provide with a set of helpers for better readability and to avoid the hassle of writing common transforms. You can find those helpers exported in a ssp variable from the same package.

<script lang="ts">
	import { ssp, queryParam } from 'sveltekit-search-params';

	const count = queryParam('count', ssp.number());
</script>

The count is {$count}
<input bind:value={$count} type="number" />

this code will produce the same output as the code written above but far more readable and easier to read. You can find all the exports documented in the section ssp - Helpers.

You can also pass a default value to the function that will be the defaultValue of the object.

<script lang="ts">
	import { ssp, queryParam } from 'sveltekit-search-params';

	const count = queryParam('count', ssp.number(10));
</script>

The count is {$count}
<input bind:value={$count} type="number" />

Simple case (all parameters)

You can use the function queryParameters to get an object containing all the present search params.

<script lang="ts">
	import { queryParameters } from 'sveltekit-search-params';

	const store = queryParameters();
</script>

<pre>
    {JSON.stringify($store, null, 2)}
</pre>

assuming the page is /?framework=svelte&isCool=true the above code will show

{
	"framework": "svelte",
	"isCool": "true"
}

by default all query parameters are string.

Writing to the store (all parameters)

Just like with the single parameter case you can just update the store and the URL at the same time by doing this

<script lang="ts">
	import { queryParameters } from 'sveltekit-search-params';

	const store = queryParameters();
</script>

<pre>
    {JSON.stringify($store, null, 2)}
</pre>
<input
	value={$store.username}
	on:input={(e) => {
		$store.username = e.target.value;
	}}
/>

writing in the input will update the state and the URL at the same time.

Expecting some parameters

Most of the times if you need to read from query parameters you are expecting some parameters to be present. You can define the parameters you are expecting during the store creating and those will be merged with the actual query parameters despite the fact that they are present or not.

<script lang="ts">
	import { queryParameters } from 'sveltekit-search-params';

	const store = queryParameters({
		username: true,
	});
</script>

<pre>
    {JSON.stringify($store, null, 2)}
</pre>

assuming the page is /?framework=svelte&isCool=true the above code will show

{
	"framework": "svelte",
	"isCool": "true",
	"username": null
}

if we add username to the URL like this /?framework=svelte&isCool=true&username=paoloricciuti we will get

{
	"framework": "svelte",
	"isCool": "true",
	"username": "paoloricciuti"
}

Encoding and Decoding

The parameter passed to queryParameters can aslo be used to specify the encoding and decoding just like the queryParam method.

<script lang="ts">
	import { queryParameters } from 'sveltekit-search-params';

	const store = queryParameters({
		username: true,
		isCool: {
			encode: (booleanValue) => booleanValue.toString(),
			decode: (stringValue) =>
				stringValue !== null && stringValue !== 'false',
			defaultValue: true,
		},
	});
</script>

<pre>
    {JSON.stringify($store, null, 2)}
</pre>

assuming the page is /?framework=svelte&isCool=true&username=paoloricciuti the above code will show

{
	"framework": "svelte",
	"isCool": true,
	"username": null
}

notice that this time isCool it's a boolean and not a string anymore. With this particular transformation we've assured that if the url is the following /?framework=svelte&isCool=false&username=paoloricciuti or if the isCool parameter is completely missing like this /?framework=svelte&username=paoloricciuti we will get

{
	"framework": "svelte",
	"isCool": false,
	"username": null
}

Helpers encodings and decodings

Obviously also in this case you can use the helpers functions provided inside ssp.

<script lang="ts">
	import { ssp, queryParameters } from 'sveltekit-search-params';

	const store = queryParameters({
		username: true,
		isCool: ssp.boolean(true),
	});
</script>

<pre>
    {JSON.stringify($store, null, 2)}
</pre>

ssp - Helpers

There are six helpers all exported as functions on the object ssp. To each one of them you can pass a parameter that will be the default value for that query param.

object

To map from a query parameter to an object. An url like this /?obj={"isComplex":%20true,%20"nested":%20{"field":%20"value"}} will be mapped to

$store.obj.isComplex; //true
$store.obj.nested; // {field: "value"}
$store.obj.nested.value; // "value"

array

To map from a query parameter to an array. An url like this /?arr=[1,2,3,4] will be mapped to

$store.arr[0]; //1
$store.arr[1]; //2
$store.arr[2]; //3
$store.arr[3]; //4

number

To map from a query parameter to a number. An url like this /?num=1 will be mapped to

$store.num; //1

boolean

To map from a query parameter to a boolean. An url like this /?bool=true will be mapped to

$store.bool; //true

as we've seen an url like this /?bool=false will be mapped to

$store.bool; //false

just like an url like this /

string

This is exported mainly for readability since all query parameters are already strings.

lz

To map any JSON serializable state to his lz-string representation. This is a common way to store state in query parameters that will prevent the link to directly show the state.

An url like this /?state=N4IgbghgNgrgpiAXCAsgTwAQGMD2OoYCO8ATpgA4QkQC2cALnCSAL5A will map to

$store.state.value; //My cool query parameter

Store options

Both functions accept a configuration object that contains the following properties:

debounceHistory

The number of milliseconds to delay the writing of the history when the state changes. This is to avoid cluttering the history of the user especially when a store is bound to an input text (every keystroke would cause a new history entry). It defaults to 0. If set a new entry in the history will be added only after debounceHistory seconds of "inactivity".

pushHistory

A boolean defining if the history have to be written at all. If set to false no new history entries will be written to the history stack (the URL will still update but the user will not be able to go back with the browser).

sort

Whenever you interact with a store, it navigates for you. By default the search params are sorted to allow for better cache-ability. You can disable this behavior by passing false to this option. Keep in mind that this is a per-store settings. This mean that if you interact with a store that has this option set to false and than interact with one that has this option set to true (the default) the resulting URL will still have the search params sorted.

showDefaults

If you specify a default value for the search param and it's not present by default the library will immediately navigate to the url that contains the default search param. For example if you have this code

<script lang="ts">
	import { queryParam, ssp } from 'sveltekit-search-params';

	const pageNum = queryParam('pageNum', ssp.number(0));
</script>

and you navigate to / as soon as the page load it will be redirected to /?pageNum=0. If you prefer not to show the defaults in the URL you can set the showDefaults option to false.

<script lang="ts">
	import { queryParam, ssp } from 'sveltekit-search-params';

	const pageNum = queryParam('pageNum', ssp.number(0), {
		showDefaults: false,
	});
</script>

By doing so the store will still have a value of 0 if the search param is not present but the user will not be redirected to /?pageNum=0.

equalityFn

While this is not a problem for primitive values if your store has a complex object or an array (or if you are using queryParameters) as a value even if the reference is the same svelte will trigger reactivity for it. To provide you with optimistic updates there's the possibility that the store will change multiple times during a single navigation. To fix this problem by default we check if the value of the store is the same by using JSON.stringify so that if the overall shape of your store is the same we avoid triggering the reactivity.

This is fine for most cases and you will likely never touch this option but if you have some use case not covered by JSON.stringify you can specify the option equalityFn. This option is a function that takes the current value and the next value as parameters and need to return a boolean. You should return true from this function when the value of the store is unchanged (according to your own logic). This will not trigger reactivity (note that the navigation will still happen).

For queryParameters the equality function applies to the entire store (so make sure to check that every query parameter is exactly the same before returning true).

<script lang="ts">
	import { queryParam, ssp } from 'sveltekit-search-params';

	const pageNum = queryParam('pageNum', ssp.object<{ num: number }>(), {
		equalityFn(current, next) {
			return current?.num === next?.num;
		},
	});
</script>

NOTE: the equality function will not be used on primitive values, hence you can't pass the equality function to stores that have a primitive type.

How to use it

To set the configuration object you can pass it as a third parameter in case of queryParam or the second in case of queryParameters.

<script lang="ts">
	import { ssp, queryParameters, queryParam } from 'sveltekit-search-params';
	const name = queryParam('name', ssp.string(), {
		debounceHistory: 500, //a new history entry will be created after 500ms of this store not changing
	});
	const count = queryParam('count', ssp.number(), {
		debounceHistory: 1500, //a new history entry will be created after 1500ms of this store not changing
	});
	const store = queryParameters(
		{
			username: true,
			isCool: ssp.boolean(true),
		},
		{
			pushHistory: false, //no new history entries for this store
		},
	);
</script>

Vite dependecies error

If you ran into issues with vite you need to update your vite.config.ts or vite.config.js file to include the plugin exported from sveltekit-search-params/plugin. It's as simple as

import { sveltekit } from '@sveltejs/kit/vite';
import { ssp } from 'sveltekit-search-params/plugin';

/** @type {import('vite').UserConfig} */
const config = {
	plugins: [ssp(), sveltekit()],
};

export default config;

Warning

This step is required if you are running on an old version of vite/sveltekit

sveltekit-search-params's People

Contributors

danielimmke avatar dominikg avatar dragon-hatcher avatar github-actions[bot] avatar paoloricciuti avatar paoramati avatar travelingtice avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

sveltekit-search-params's Issues

Updating to SvelteKit 2 leads to warning

Describe the bug

We just updated from "@sveltejs/kit": "^1.24.1" to "@sveltejs/kit": "^2.5.0" and started getting the warning:

Avoid using history.pushState(...) and history.replaceState(...) as these will conflict with SvelteKit's router. Use the pushState and replaceState imports from $app/navigation instead.

Reproduction

This just happens every time we write to the query-params.

Logs

No response

Using update function from queryParam store doesn't update the url

i notice this when i building my pagination component, i use this code
const current_page = queryParam("page", ssp.number(1));\
and using this button to go to previous page
<button class="grid place-items-center bg-white border-gray-600 shadow-md" on:click={() => current_page.update((e) => { const new_val = Math.max((e ?? 1) - 1, 1); return new_val; })} > &lt; </button>
the current_page state gets updated but the brower url doesn't.

Error exporting compressToEncodedURIComponent

client-manifest.js:28 SyntaxError: The requested module '/node_modules/.pnpm/[email protected]/node_modules/lz-string/libs/lz-string.js?v=2285ece9' does not provide an export named 'compressToEncodedURIComponent' (at sveltekit-search-params.js?v=2285ece9:7:10)
handleError @ client-manifest.js:28

using:

"@sveltejs/adapter-auto": "next",
"@sveltejs/kit": "1.0.0-next.561",

Unsubscribing

I noticed when I go to different page routes my search params are persisting, and I think it's because I need to unsubscribe() during an onDestroy() lifecycle hook. Would you consider returning the subscription that you have here?

URL #hash being removed on update

Describe the bug

Hi, I am excited to use your plugin as it does everything I need to maintain state using query params, thank you for developing it!

I noticed that when I update a queryParam, it seems to remove the #hash portion of the URL. I assume this is not intentional?

As you can see in my reproduction steps below, I am using maplibre-gl which maintains its map state in the URL hash automatically, so I'd like to leave it untouched.

Reproduction

// Current URL: http://localhost/#10/29.42/-98.47
const search = queryParam('q', ssp.string());
$search = 'foo';
// New URL: http://localhost/?q=foo

Logs

No response

Array helper default value not typed correctly

Describe the bug

Thanks for this awesome library!

Simple issue - the default value of an array param when using the ssp.array() helper is not typed correctly.

Currently we have

    array: <T = any>(defaultValue?: T) => ({
        encode: (value: T[]) => JSON.stringify(value),
        decode: (value: string | null): T[] | null => {
            if (value === null) return null;
            try {
                return JSON.parse(value);
            } catch (e) {
                return null;
            }
        },
        defaultValue,
    }),

The default value should be typed as T[] and not T.

Reproduction

Logs

No response

hiding default value with arrays and objects

Describe the bug

Not sure if this is a bug, but let me explain.

When I create a new query param store with an empty array as the default value and showDefaults set to false, everything is fine on the first load. The query param is not added to the URL.

Adding an element to the array and the URL updates accordingly.

But now when I remove the object again or assign [] to the store, the query param is added to the URL with an empty array value.

@paoloricciuti Would love to hear you opinion on what the expected behavior should be. IMO the query param should disappear again after it has been reset to its default value.

Already have an idea that the issue comes from comparison by reference instead of comparison by value, but want to wait for your feedback first, before jumping into any code.

Cheers!

Reproduction

// creating the store, no query param in the URL
const params = queryParam('params', ssp.array([]), { showDefaults: false });

// adding element to store array, URL updates to ?params=["foo"]
$params = ['foo']

// resetting store to empty array, URL updates to ?params=[]
$params = []

Logs

No response

Optimistic store updates, update store before navigation happens.

Describe the problem

When writing to a query param the store only updates once the navigation has finished, this can cause a non-instant change when using user input like a select. This feels janky and isn't good UX. This is especially noticable when load functions are doing work since navigation only resolves once the load function finishes.

Describe the proposed solution

I don't know if this is technically feasable within the library but my proposal is to optimistically update the store. So instead of just mutating the URL and letting the subscribe handle the updates you can optimistically set the store before the navigation even happens so the store is updated immediately.
Downside would be that the update would cause subscribers to get notified 2 times. (Unless you can detect the value was updated optimistically and only update if the optimistic value doesn't match the actual URL value).

Possible bug: Inconsistent behavior with Node 20

Describe the bug

First off, I'll say that I haven't verified if this happens without the use of your plugin.

const search = queryParam('q', ssp.string(), {pushHistory: false})
...
<input type="search" name="search" placeholder="Search" bind:value={$search} />

Running this on Node 18, no calls to __data.json happen when typing in the input. But when I upgrade to Node 20, I see a request to __data.json on every keystroke.

It took me a looong time to figure out what the culprit was. I created a whole Stackblitz for you, only to find that the issue wasn't there because apparently it runs Node 16.

Reproduction

https://stackblitz.com/edit/sveltejs-kit-template-default-d1rzdh?file=README.md

Logs

No response

Initial store value is undefined for param with defaultValue set

Describe the bug

creating a store and immediately accessing it in the root layout while defining a parameter with a default value causes the initial value to be undefined.

In the reproduction, there is a parameter "foo" with default "bar". accessing /, the url is updated to include ?foo=bar but the initial value in +layout.svelte is undefined.

This is unexpected and causes an error if you want to access $params.foo.

Possible solutions:

  • Do not render default values in the url, but reflect them in the store if the url does not set a different value
  • Fall back to default value if url does not supply it

Reproduction

https://www.sveltelab.dev/49is8k7v2xv3ap3

Logs

No response

Allow encoding as undefined to remove param

Describe the problem

If there is a default version of a parameter it can be nice to not have it show up in the URL.

Describe the proposed solution

If encode returns undefined delete the parameter from the url.

Usage in derived storage

Describe the problem

I would like to do some computations in a derived store based on values returned from queryParameters but can't figure out how. I guess that it may currently not be possible based on how queryParameters is exported? Currently it's exported as a function but the derived store expects a writable store as an argument.

Describe the proposed solution

It would be great to have an exported writable store that could be used as such:

export const derivedStore = derived([queryParameters, anotherStore], ([$queryParameters, $anotherStore]) => {
   const { param1, param2, ... } = $queryParameters;
   // ... 
});

Reset search param A when search param B changes - Unexpected behaviour

Describe the bug

Hi,

I have 2 search parameters:

  1. Page: This is used for pagination.
  2. Ingredients: This is used for filtering shakes by ingredients.

Imagine a user is on page 2 and then selects an ingredient. At this moment, I want to reset the page to "1" to start from the beginning. In fact, this reset may occur each time the filter is updated.

Here's how I achieve this:

const currentPage = queryParam('page', ssp.number(1))
const selectedIngredients = queryParam('ingredients', ssp.array([]), { showDefaults: false })

selectedIngredients.subscribe((value) => {
  if (!value) {
    return;   
  }
  currentPage.set(1)
})

Unfortunately, the filters stop working with this logic. It becomes impossible to check/uncheck ingredients.

Reproduction

https://codesandbox.io/p/devbox/multiple-filters-srqnmf?file=%2Fsrc%2Flib%2Fcomponents%2FIngredientsFilter.svelte%3A13%2C1-18%2C6

Logs

No response

Value is nullable if default value is provided

Describe the bug

image

type of page should be Writable<number>

Reproduction

<script>
  import { queryParam, ssp } from "sveltekit-search-params";

  $: page = queryParam("p", ssp.number());
</script>

Logs

No response

Support for bind:group directive

Describe the problem

In Svelte, you can use the bind:group feature like so:

<script lang="ts">
    let selected = []
</script>

<input type="checkbox" bind:group={selected} value="2022" />
<input type="checkbox" bind:group={selected} value="2023" />
<input type="checkbox" bind:group={selected} value="2024" />

However, when attempting to apply the same technique with the (awesome! ๐Ÿ˜Ž) sveltekit-search-params package, as shown:

<script lang="ts">
    import { ssp, queryParam } from 'sveltekit-search-params';

    const selected = queryParam('years', ssp.array());
</script>

<input type="checkbox" bind:group={$selected} value="2022" />
<input type="checkbox" bind:group={$selected} value="2023" />
<input type="checkbox" bind:group={$selected} value="2024" />

An error occurs:

TypeError: Cannot read properties of null (reading 'indexOf')

Describe the proposed solution

It's possible that there's an error in my implementation, or perhaps this feature isn't supported yet. Regardless, having this functionality would be fantastic.

Potential uncaught error message?

Describe the bug

Hello,

We've chatted before. Thanks again for creating this super helpful package. I'd donate to you if there was an option for it (is there?)

I wanted to report something I have been getting in my logs on any page that uses this package. I checked the stack trace and it appears that goto is being called a total of 4 times in the main sveltekit-search-params.js file. It's possible I have things setup in an unusual way where SvelteKit tries to execute this code on the server - I have a lot of logic about how navigation happens in my app. This happens on a page where I use debounceHistory and a page where I don't.

I'm not sure I will be able to repro it, but I will try later today. But I think adding a if(browser) guard before the goto calls would maybe fix the issue? Even if it's not something that only occurs in edge cases.

Screenshot 2023-04-20 at 8 53 49 AM

Reproduction

N/A

Logs

No response

defaultValue not applyed in a second client side navigation

Describe the bug

I have this setting:

const store_qp = queryParameters({
  withOne: ssp.boolean(true),
  withTwo: ssp.boolean(false),
  
  pushHistory: false,
})

First time I see the page, I see my queryParams getting updated, it's all good.
Then, I navigate (client side), and when at some point I go back to this page, defaults don't get applied.

When, I leave the page, my +page.svelte get destoyed well. So I'm not sure what's happening.

Thanks for your help

Reproduction

https://www.sveltelab.dev/?provider=github&owner=jycouet&repo=veltekit-search-params-default-value

  1. Navigate to Page A
    โœ… query param are displayed and applied
  2. Navigate to Page B
    โœ… Nothing special, it's going there
  3. Navigate to Page A
    โŒ Default query params are not applied.

Logs

No response

Remove empty query string.

Describe the bug

How do I get an empty query string off the URL?

Reproduction

Add with data then try to remove.

Logs

No response

Debouncing updates

it can be nasty to the browser history when we type and the url bar is updated on every keystroke.

could we offer an easy way (probably not default, but recommended) to debounce the updates?

Unable to navigate to other pages

Describe the bug

After I open a page with this library configured I cannot navigate to any other page.
The URL does change but my app still shows the same page which is using sveltekit-search-params

Reproduction

Will setup a reproduction and add here.

Logs

No response

sort params in url to improve browser cache hit rate

Describe the problem

With optional parameters it is currently possible to add them at different times, and their insertion order determines their position in the query string of the url.

http caching uses the full url , so https://example.com?a=1&b=2 is a different entry than https://example.com?b=2&a=1
In order to have a more stable url representation and improve cache hit rate, it would be great if the params can be sorted.

Describe the proposed solution

use native sort() by default, add an option for custom sort function (or false to disable)

Crashes with enabled prerendering

Describe the bug

When queryParam is used on a page that has enabled sveltekit prerendering, the build crashes. This in theory is understandable because obviously there are no query parameters during build. However, I would expect the behavior to be the same as in during SSR: I get null and wait for hydration.

Reproduction

Minimal reproduction repo: https://github.com/shilangyu/sveltekit-search-params-prerender

Run npm run build to see the problem.

Logs

Error: Cannot access url.searchParams on a page with prerendering enabled
    at URL.get (file:///Users/marcinwojnarowski/coding/temp/svelte-kit-prerender-query/.svelte-kit/output/server/chunks/exports.js:92:15)
    at file:///Users/marcinwojnarowski/coding/temp/svelte-kit-prerender-query/.svelte-kit/output/server/entries/pages/_page.svelte.js:22:35
    at sync (file:///Users/marcinwojnarowski/coding/temp/svelte-kit-prerender-query/.svelte-kit/output/server/chunks/index.js:66:22)
    at file:///Users/marcinwojnarowski/coding/temp/svelte-kit-prerender-query/.svelte-kit/output/server/chunks/index.js:89:5
    at Object.subscribe2 [as subscribe] (file:///Users/marcinwojnarowski/coding/temp/svelte-kit-prerender-query/.svelte-kit/output/server/chunks/index.js:36:14)
    at subscribe (file:///Users/marcinwojnarowski/coding/temp/svelte-kit-prerender-query/.svelte-kit/output/server/chunks/ssr.js:25:23)
    at file:///Users/marcinwojnarowski/coding/temp/svelte-kit-prerender-query/.svelte-kit/output/server/entries/pages/_page.svelte.js:49:25
    at Object.$$render (file:///Users/marcinwojnarowski/coding/temp/svelte-kit-prerender-query/.svelte-kit/output/server/chunks/ssr.js:87:18)
    at Object.default (file:///Users/marcinwojnarowski/coding/temp/svelte-kit-prerender-query/.svelte-kit/output/server/chunks/internal.js:80:98)
    at file:///Users/marcinwojnarowski/coding/temp/svelte-kit-prerender-query/.svelte-kit/output/server/entries/fallbacks/layout.svelte.js:3:42

node:internal/event_target:1096
  process.nextTick(() => { throw err; });
                           ^
Error: 500 /
To suppress or handle this error, implement `handleHttpError` in https://kit.svelte.dev/docs/configuration#prerender
    at file:///Users/marcinwojnarowski/coding/temp/svelte-kit-prerender-query/node_modules/@sveltejs/kit/src/core/config/options.js:202:13
    at file:///Users/marcinwojnarowski/coding/temp/svelte-kit-prerender-query/node_modules/@sveltejs/kit/src/core/postbuild/prerender.js:65:25
    at save (file:///Users/marcinwojnarowski/coding/temp/svelte-kit-prerender-query/node_modules/@sveltejs/kit/src/core/postbuild/prerender.js:403:4)
    at visit (file:///Users/marcinwojnarowski/coding/temp/svelte-kit-prerender-query/node_modules/@sveltejs/kit/src/core/postbuild/prerender.js:236:3)

Node.js v21.6.1

Remove the query string from the URL when a parameter isn't set

Describe the problem

I have a search query string parameter bound to a search input field. Ideally, when the search input field is empty, I'd like to see the search query string disappear from the URL. Currently, it shows ?search=.

Describe the proposed solution

The current solution is this:

function nullableQueryParam<T>({
  encode,
  ...codec
}: EncodeAndDecodeOptions<T>) {
  return {
    ...codec,
    encode(value) {
      if (value === "") return undefined;
      if (Array.isArray(value) && value.length === 0) return undefined;

      return encode(value);
    },
  } as EncodeAndDecodeOptions<T>;
}

Then use it as follows:

export function getUrlSearchParamsFiltersStore() {
  return queryParam<string[]>("filters", nullableQueryParam(ssp.array()));
}

Cannot find package '$app'

Describe the bug

Whenever I do a hard refresh, I get this error. Not sure what I am missing!

Reproduction

https://stackblitz.com/edit/sveltejs-kit-template-default-c78wrs?file=src%2Froutes%2F%2Bpage.svelte

Logs

00:48:40 [vite] Error when evaluating SSR module /src/routes/+page.svelte: failed to import "sveltekit-search-params"
|- Error [ERR_MODULE_NOT_FOUND]: Cannot find package '$app' imported from /home/projects/sveltejs-kit-template-default-c78wrs/node_modules/sveltekit-search-params/package/sveltekit-search-params.js
    at  (https://sveltejskittemplatedefaultc78w-xkpr.w-corp.staticblitz.com/blitz.95086023.js:36:4170)
    at packageResolve (https://sveltejskittemplatedefaultc78w-xkpr.w-corp.staticblitz.com/blitz.95086023.js:114:9613)
    at  (https://sveltejskittemplatedefaultc78w-xkpr.w-corp.staticblitz.com/blitz.95086023.js:114:11319)
    at  (https://sveltejskittemplatedefaultc78w-xkpr.w-corp.staticblitz.com/blitz.95086023.js:114:12167)
    at defaultResolve (https://sveltejskittemplatedefaultc78w-xkpr.w-corp.staticblitz.com/blitz.95086023.js:114:12837)
    at  (https://sveltejskittemplatedefaultc78w-xkpr.w-corp.staticblitz.com/blitz.95086023.js:248:2121)
    at  (https://sveltejskittemplatedefaultc78w-xkpr.w-corp.staticblitz.com/blitz.95086023.js:248:2213)
    at  (https://sveltejskittemplatedefaultc78w-xkpr.w-corp.staticblitz.com/blitz.95086023.js:248:7557)
    at resolve (https://sveltejskittemplatedefaultc78w-xkpr.w-corp.staticblitz.com/blitz.95086023.js:248:7997)
    at  (https://sveltejskittemplatedefaultc78w-xkpr.w-corp.staticblitz.com/blitz.95086023.js:248:4394)
    at getModuleJob (https://sveltejskittemplatedefaultc78w-xkpr.w-corp.staticblitz.com/blitz.95086023.js:248:4673)
    at  (https://sveltejskittemplatedefaultc78w-xkpr.w-corp.staticblitz.com/blitz.95086023.js:181:944)
    at  (https://sveltejskittemplatedefaultc78w-xkpr.w-corp.staticblitz.com/blitz.95086023.js:181:989)
    at  (https://sveltejskittemplatedefaultc78w-xkpr.w-corp.staticblitz.com/blitz.95086023.js:352:382940)
    at  (https://sveltejskittemplatedefaultc78w-xkpr.w-corp.staticblitz.com/blitz.95086023.js:181:897)

Error [ERR_MODULE_NOT_FOUND]: Cannot find package '$app' imported from /home/projects/sveltejs-kit-template-default-c78wrs/node_modules/sveltekit-search-params/package/sveltekit-search-params.js
    at  (https://sveltejskittemplatedefaultc78w-xkpr.w-corp.staticblitz.com/blitz.95086023.js:36:4170)
    at packageResolve (https://sveltejskittemplatedefaultc78w-xkpr.w-corp.staticblitz.com/blitz.95086023.js:114:9613)
    at  (https://sveltejskittemplatedefaultc78w-xkpr.w-corp.staticblitz.com/blitz.95086023.js:114:11319)
    at  (https://sveltejskittemplatedefaultc78w-xkpr.w-corp.staticblitz.com/blitz.95086023.js:114:12167)
    at defaultResolve (https://sveltejskittemplatedefaultc78w-xkpr.w-corp.staticblitz.com/blitz.95086023.js:114:12837)
    at  (https://sveltejskittemplatedefaultc78w-xkpr.w-corp.staticblitz.com/blitz.95086023.js:248:2121)
    at  (https://sveltejskittemplatedefaultc78w-xkpr.w-corp.staticblitz.com/blitz.95086023.js:248:2213)
    at  (https://sveltejskittemplatedefaultc78w-xkpr.w-corp.staticblitz.com/blitz.95086023.js:248:7557)
    at resolve (https://sveltejskittemplatedefaultc78w-xkpr.w-corp.staticblitz.com/blitz.95086023.js:248:7997)
    at  (https://sveltejskittemplatedefaultc78w-xkpr.w-corp.staticblitz.com/blitz.95086023.js:248:4394)
    at getModuleJob (https://sveltejskittemplatedefaultc78w-xkpr.w-corp.staticblitz.com/blitz.95086023.js:248:4673)
    at  (https://sveltejskittemplatedefaultc78w-xkpr.w-corp.staticblitz.com/blitz.95086023.js:181:944)
    at  (https://sveltejskittemplatedefaultc78w-xkpr.w-corp.staticblitz.com/blitz.95086023.js:181:989)
    at  (https://sveltejskittemplatedefaultc78w-xkpr.w-corp.staticblitz.com/blitz.95086023.js:352:382940)
    at  (https://sveltejskittemplatedefaultc78w-xkpr.w-corp.staticblitz.com/blitz.95086023.js:181:897) {
  code: 'ERR_MODULE_NOT_FOUND'
}

Type error with exactOptionalPropertyTypes on

Describe the bug

Given this code:

const booleanFilters = queryParam('bf', ssp.array<string>([]));

I get this typescript error when exactOptionalPropertyTypes is true in my tsconfig

Argument of type '{ encode: (value: string[]) => string; decode: (value: string | null) => string[] | null; defaultValue: string[] | undefined; }' is not assignable to parameter of type 'EncodeAndDecodeOptions<string[]>' with 'exactOptionalPropertyTypes: true'. Consider adding 'undefined' to the types of the target's properties.
  Types of property 'defaultValue' are incompatible.
    Type 'string[] | undefined' is not assignable to type 'string[]'.
      Type 'undefined' is not assignable to type 'string[]'.ts(2379)

Reproduction

import { ssp, queryParam } from 'sveltekit-search-params';

const booleanFilters = queryParam('bf', ssp.array<string>([]));

Logs

No response

Setting a default if enumerated parameter is invalid

Describe the problem

Provide an api to check validity of query keys and provide defaults if invalid.

For whatever reason some users try to modify our search params manually. We assume this mostly happens when a url not fully copied to the clipboard. Nonetheless you'll end up with a query that looks like ?sort=highes for example; where the "t" is cutoff.

At the moment we are the default parameter but that only adds a default value if the key is not present instead of checking if the value is valid it seems.

We are currently checking this in our onMount like so; but it gets verbose when there are 15 keys to check for (search heavy data app).

	onMount(() => {
		if ($store.sort !== 'highest' ?? $store.sort !== 'recent') {
			$store.sort = 'highest';
		}
	});

Describe the proposed solution

An api similar to the default feature that would not only check for a missing key, but check for its validity and set a default value if invalid.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.