Skip to content

Commit

Permalink
feat: migrate from qs
Browse files Browse the repository at this point in the history
Moves the `manager-api`, `preview-api` and `ui/amanger` to use
`picoquery` instead of `qs` - a much smaller and faster alternative.

Note that we still have `qs` in our overall monorepo tree, but that can
be tackled in a follow-up PR.
  • Loading branch information
43081j committed Jun 23, 2024
1 parent 1943ee6 commit 050044f
Show file tree
Hide file tree
Showing 9 changed files with 49 additions and 33 deletions.
1 change: 0 additions & 1 deletion code/lib/manager-api/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,6 @@
},
"devDependencies": {
"@types/lodash": "^4.14.167",
"@types/qs": "^6",
"@types/semver": "^7.3.4",
"flush-promises": "^1.0.2",
"react": "^18.2.0",
Expand Down
3 changes: 1 addition & 2 deletions code/lib/preview-api/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,11 +50,10 @@
"@storybook/csf": "^0.1.8",
"@storybook/global": "^5.0.0",
"@storybook/types": "workspace:*",
"@types/qs": "^6.9.5",
"dequal": "^2.0.2",
"lodash": "^4.17.21",
"memoizerific": "^1.11.3",
"qs": "^6.10.0",
"picoquery": "^1.0.0",
"tiny-invariant": "^1.3.1",
"ts-dedent": "^2.0.0",
"util-deprecate": "^1.0.2"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,5 @@ export interface SelectionStore {

setSelection(selection: Selection): void;

setQueryParams(queryParams: qs.ParsedQs): void;
setQueryParams(queryParams: Record<PropertyKey, unknown>): void;
}
4 changes: 2 additions & 2 deletions code/lib/preview-api/src/modules/preview-web/UrlStore.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ describe('UrlStore', () => {
);
});
it('should replace legacy parameters but preserve others', () => {
document.location.search = 'foo=bar&selectedStory=selStory&selectedKind=selKind';
document.location.search = '?foo=bar&selectedStory=selStory&selectedKind=selKind';
setPath({ storyId: 'story--id', viewMode: 'story' });
expect(history.replaceState).toHaveBeenCalledWith(
{},
Expand All @@ -48,7 +48,7 @@ describe('UrlStore', () => {
);
});
it('should ignore + keep hashes', () => {
document.location.search = 'foo=bar&selectedStory=selStory&selectedKind=selKind';
document.location.search = '?foo=bar&selectedStory=selStory&selectedKind=selKind';
document.location.hash = '#foobar';
setPath({ storyId: 'story--id', viewMode: 'story' });
expect(history.replaceState).toHaveBeenCalledWith(
Expand Down
36 changes: 20 additions & 16 deletions code/lib/preview-api/src/modules/preview-web/UrlStore.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { global } from '@storybook/global';
import qs from 'qs';
import * as pq from 'picoquery';
import type { ViewMode } from '@storybook/types';

import { parseArgsParam } from './parseArgsParam';
Expand All @@ -20,19 +20,20 @@ const getQueryString = ({
extraParams,
}: {
selection?: Selection;
extraParams?: qs.ParsedQs;
extraParams?: Record<PropertyKey, unknown>;
}) => {
const search = typeof document !== 'undefined' ? document.location.search : '';
const { path, selectedKind, selectedStory, ...rest } = qs.parse(search, {
ignoreQueryPrefix: true,
});
return qs.stringify(
{
const search =
typeof document !== 'undefined' && document.location.search
? document.location.search.slice(1)
: '';
const { path, selectedKind, selectedStory, ...rest } = pq.parse(search);
return (
'?' +
pq.stringify({
...rest,
...extraParams,
...(selection && { id: selection.storyId, viewMode: selection.viewMode }),
},
{ encode: false, addQueryPrefix: true }
})
);
};

Expand All @@ -45,10 +46,10 @@ export const setPath = (selection?: Selection) => {
};

type ValueOf<T> = T[keyof T];
const isObject = (val: Record<string, any>) =>
const isObject = (val: Record<string, any>): val is object =>
val != null && typeof val === 'object' && Array.isArray(val) === false;

const getFirstString = (v: ValueOf<qs.ParsedQs>): string | void => {
const getFirstString = (v: ValueOf<Record<PropertyKey, unknown>>): string | void => {
if (v === undefined) {
return undefined;
}
Expand All @@ -58,15 +59,18 @@ const getFirstString = (v: ValueOf<qs.ParsedQs>): string | void => {
if (Array.isArray(v)) {
return getFirstString(v[0]);
}
if (isObject(v)) {
return getFirstString(Object.values(v).filter(Boolean) as string[]);
if (isObject(v as Record<PropertyKey, unknown>)) {
return getFirstString(
Object.values(v as Record<PropertyKey, unknown>).filter(Boolean) as string[]
);
}
return undefined;
};

export const getSelectionSpecifierFromPath: () => SelectionSpecifier | null = () => {
if (typeof document !== 'undefined') {
const query = qs.parse(document.location.search, { ignoreQueryPrefix: true });
const queryStr = document.location.search ? document.location.search.slice(1) : '';
const query = pq.parse(queryStr);
const args = typeof query.args === 'string' ? parseArgsParam(query.args) : undefined;
const globals = typeof query.globals === 'string' ? parseArgsParam(query.globals) : undefined;

Expand Down Expand Up @@ -100,7 +104,7 @@ export class UrlStore implements SelectionStore {
setPath(this.selection);
}

setQueryParams(queryParams: qs.ParsedQs) {
setQueryParams(queryParams: Record<PropertyKey, unknown>) {
const query = getQueryString({ extraParams: queryParams });
const { hash = '' } = document.location;
history.replaceState({}, '', `${document.location.pathname}${query}${hash}`);
Expand Down
2 changes: 1 addition & 1 deletion code/lib/router/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@
"dependencies": {
"@storybook/client-logger": "workspace:*",
"memoizerific": "^1.11.3",
"qs": "^6.10.0"
"picoquery": "^1.0.0"
},
"devDependencies": {
"@storybook/global": "^5.0.0",
Expand Down
2 changes: 1 addition & 1 deletion code/ui/manager/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -97,8 +97,8 @@
"lodash": "^4.17.21",
"markdown-to-jsx": "^7.4.5",
"memoizerific": "^1.11.3",
"picoquery": "^1.0.0",
"polished": "^4.2.2",
"qs": "^6.10.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-draggable": "^4.4.5",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import qs from 'qs';
import { stringify } from 'picoquery';

export const stringifyQueryParams = (queryParams: Record<string, string>) =>
qs.stringify(queryParams, { addQueryPrefix: true, encode: false }).replace(/^\?/, '&');
'&' + stringify(queryParams);
28 changes: 21 additions & 7 deletions code/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -6232,7 +6232,6 @@ __metadata:
"@storybook/theming": "workspace:*"
"@storybook/types": "workspace:*"
"@types/lodash": "npm:^4.14.167"
"@types/qs": "npm:^6"
"@types/semver": "npm:^7.3.4"
dequal: "npm:^2.0.2"
flush-promises: "npm:^1.0.2"
Expand Down Expand Up @@ -6277,8 +6276,8 @@ __metadata:
lodash: "npm:^4.17.21"
markdown-to-jsx: "npm:^7.4.5"
memoizerific: "npm:^1.11.3"
picoquery: "npm:^1.0.0"
polished: "npm:^4.2.2"
qs: "npm:^6.10.0"
react: "npm:^18.2.0"
react-dom: "npm:^18.2.0"
react-draggable: "npm:^4.4.5"
Expand Down Expand Up @@ -6568,12 +6567,11 @@ __metadata:
"@storybook/csf": "npm:^0.1.8"
"@storybook/global": "npm:^5.0.0"
"@storybook/types": "workspace:*"
"@types/qs": "npm:^6.9.5"
ansi-to-html: "npm:^0.6.11"
dequal: "npm:^2.0.2"
lodash: "npm:^4.17.21"
memoizerific: "npm:^1.11.3"
qs: "npm:^6.10.0"
picoquery: "npm:^1.0.0"
slash: "npm:^5.0.0"
tiny-invariant: "npm:^1.3.1"
ts-dedent: "npm:^2.0.0"
Expand Down Expand Up @@ -6877,7 +6875,7 @@ __metadata:
dequal: "npm:^2.0.2"
lodash: "npm:^4.17.21"
memoizerific: "npm:^1.11.3"
qs: "npm:^6.10.0"
picoquery: "npm:^1.0.0"
react: "npm:^18.2.0"
react-dom: "npm:^18.2.0"
react-router-dom: "npm:6.0.2"
Expand Down Expand Up @@ -8191,7 +8189,7 @@ __metadata:
languageName: node
linkType: hard

"@types/qs@npm:*, @types/qs@npm:^6, @types/qs@npm:^6.9.5":
"@types/qs@npm:*":
version: 6.9.10
resolution: "@types/qs@npm:6.9.10"
checksum: 10c0/6be12e5f062d1b41eb037d59bf9cb65bc9410cedd5e6da832dfd7c8e2b3f4c91e81c9b90b51811140770e5052c6c4e8361181bd9437ddcd4515dc128b7c00353
Expand Down Expand Up @@ -14953,6 +14951,13 @@ __metadata:
languageName: node
linkType: hard

"fast-decode-uri-component@npm:^1.0.1":
version: 1.0.1
resolution: "fast-decode-uri-component@npm:1.0.1"
checksum: 10c0/039d50c2e99d64f999c3f2126c23fbf75a04a4117e218a149ca0b1d2aeb8c834b7b19d643b9d35d4eabce357189a6a94085f78cf48869e6e26cc59b036284bc3
languageName: node
linkType: hard

"fast-deep-equal@npm:^3.1.1, fast-deep-equal@npm:^3.1.3":
version: 3.1.3
resolution: "fast-deep-equal@npm:3.1.3"
Expand Down Expand Up @@ -22493,6 +22498,15 @@ __metadata:
languageName: node
linkType: hard

"picoquery@npm:^1.0.0":
version: 1.0.0
resolution: "picoquery@npm:1.0.0"
dependencies:
fast-decode-uri-component: "npm:^1.0.1"
checksum: 10c0/d5d89ca0ce6f150db02175b072eb881460bb3dc2a7a50d55be1b4f05d953136efc3815504d93045c8ba014c318f4a4e1f523b1a960db9db0bde357bca28aacde
languageName: node
linkType: hard

"pidtree@npm:0.6.0":
version: 0.6.0
resolution: "pidtree@npm:0.6.0"
Expand Down Expand Up @@ -23340,7 +23354,7 @@ __metadata:
languageName: node
linkType: hard

"qs@npm:^6.10.0, qs@npm:^6.10.1, qs@npm:^6.11.2, qs@npm:^6.4.0":
"qs@npm:^6.10.1, qs@npm:^6.11.2, qs@npm:^6.4.0":
version: 6.11.2
resolution: "qs@npm:6.11.2"
dependencies:
Expand Down

0 comments on commit 050044f

Please sign in to comment.