sourcegraph/package.json
Felix Kling 031bb871fb
svelte: Towards a better data fetching and GraphQL authoring experience (#59383)
This PR refactors almost all of the prototypes GraphQL queries to take advantage of GraphQLs compossibility via fragments. The goal is to provide a more structured approach to authoring and executing GraphQL queries, with the following advantages:
- Data dependency co-location makes it easier to maintain/extend individual components.
- Data fetching happens in specific, predictable places (layout and page loaders).

On a high level it works like this:

- Components declare their data dependencies in `<Component>.gql` files next to them. Thanks to GraphQL code generation they can import the corresponding TypeScript types via `import type { SomeFragment} from './<Component>.gql'`.
- Higher level components compose the fragments of their children.
- At the page/layout level `page.gql`/`layout.gql` files define the queries, composed from the data dependencies of the page/layout.
- The page/layout data loaders can import queries directly from the corresponding `.gql` file.

Authoring the `.gql` files should be relatively easily if the graphql language server is setup. The changes in the `.graphlrc` file make all fragments globally available which means that every fragment needs to be unique and we don't need to use unofficial `#import` directives inside `.gql` files.

There are a couple of things to consider though:

- Caching: If different pages/layouts fetch the same data with different queries, we won't leverage caching without additional setup. That's something I still need to look into. That also means that sometimes we might want to use a shared queries instead of composition/co-location, if caching is more important.
- Shared layout data: Some data fetched in layouts is accessed by sub-layouts/sub-pages, but the layout doesn't know which sub-layout/sub-page is loaded, making query composition more difficult. So it far it seems that data shared this way is rather limited/constrained. So my current approach is to have components/pages define fragments following a specific naming convention, and have the loaders that provide this data compose them. Examples for this is `SearchInput_AuthorizedUser` and `RepoPage_ResolvedRevision`.
  This is not ideal because it has to be remembered to embed this fragment in the right place, but it's not worse than the current situation (where we often don't know where the query providing some data is defined).
- On demand data fetching: Not all data is necessary for rendering a page, some data is only fetched when in response to some user interaction. The layout/page loader should still be the place that executes the query, but instead of doing it on page load it passes a function to the page to fetch the data on demand. This way we can maintain data co-location and fetching in loaders. For an example see the `fetchCommitHistory` function.

NOTE: I expect there to be changes to this approach as we uncover more data loading requirements.
2024-01-09 10:33:30 +01:00

456 lines
16 KiB
JSON

{
"private": true,
"description": "The Sourcegraph web app",
"license": "Apache-2.0",
"repository": {
"type": "git",
"url": "https://github.com/sourcegraph/sourcegraph"
},
"engines": {
"node": "^v20.8.0",
"pnpm": "^8.9.2"
},
"scripts": {
"format": "prettier '**/{*.{js?(on),ts?(x),graphql,md,scss},.*.js?(on)}' --list-different --config prettier.config.js --write",
"format:changed": "prettier $( { git diff --diff-filter=d --name-only origin/main... && git ls-files --other --modified --exclude-standard ; } | grep -E '\\.(js|json|ts|tsx|graphql|md|scss)$' | xargs) --write --list-different --config prettier.config.js",
"format:check": "prettier '**/{*.{js?(on),ts?(x),graphql,md,scss},.*.js?(on)}' --config prettier.config.js --check --write=false",
"_lint:js": "DOCSITE_LIST=\"$(./dev/docsite.sh -config doc/docsite.json ls)\" NODE_OPTIONS=\"--max_old_space_size=16192\" eslint",
"lint:js:changed": "pnpm _lint:js $(git diff --diff-filter=d --name-only origin/main... | grep -E '\\.[tj]sx?$' | xargs)",
"lint:js:root": "pnpm run _lint:js --quiet '*.[tj]s?(x)'",
"lint:js:web": "DOCSITE_LIST=\"$(./dev/docsite.sh -config doc/docsite.json ls)\" pnpm --filter @sourcegraph/web run lint:js --quiet",
"lint:js:all": "DOCSITE_LIST=\"$(./dev/docsite.sh -config doc/docsite.json ls)\" dev/foreach-non-web-client-project.sh pnpm run lint:js --quiet && pnpm lint:js:root",
"_lint:css": "stylelint --quiet",
"lint:css:changed": "pnpm _lint:css --allow-empty-input \"*.none\" $(git diff --diff-filter=d --name-only origin/main... | grep -E '.s?css$' | xargs)",
"lint:css:all": "pnpm _lint:css 'client/*/src/**/*.scss'",
"lint:graphql": "graphql-schema-linter",
"build-ts": "tsc --build tsconfig.json --emitDeclarationOnly",
"build-web": "pnpm --filter @sourcegraph/web run build",
"watch-web": "pnpm --filter @sourcegraph/web run watch",
"generate": "pnpm --filter @sourcegraph/shared run generate",
"test": "vitest",
"_test-integration": "TS_NODE_PROJECT=client/web/src/integration/tsconfig.json mocha --parallel=${CI:-\"false\"} --retries=1 --jobs=2",
"test-integration": "NODE_ENV=production pnpm _test-integration \"./client/web/src/integration/**/*.test.ts\"",
"test-integration:debug": "BROWSER=chrome KEEP_BROWSER=true DEVTOOLS=true DISABLE_APP_ASSETS_MOCKING=true WINDOW_WIDTH=1920 WINDOW_HEIGHT=1080 pnpm _test-integration --retries=0 --jobs=1",
"test-browser-integration": "pnpm --filter @sourcegraph/browser run test-integration",
"test-e2e": "TS_NODE_PROJECT=client/web/src/end-to-end/tsconfig.json mocha ./client/web/src/end-to-end/**/*.test.ts",
"test-regression": "pnpm --filter @sourcegraph/web run test:regression",
"storybook": "pnpm --filter @sourcegraph/storybook run start",
"storybook:dll": "pnpm --filter @sourcegraph/storybook run start:dll",
"storybook:branded": "pnpm --filter @sourcegraph/branded run storybook",
"storybook:browser": "pnpm --filter @sourcegraph/browser run storybook",
"storybook:jetbrains": "pnpm --filter @sourcegraph/jetbrains run storybook",
"storybook:shared": "pnpm --filter @sourcegraph/shared run storybook",
"storybook:web": "pnpm --filter @sourcegraph/web run storybook",
"storybook:wildcard": "pnpm --filter @sourcegraph/wildcard run storybook",
"storybook:build": "pnpm --filter @sourcegraph/storybook run build",
"release": "cd dev/release && pnpm run release",
"docsite:serve": "./dev/docsite.sh -config doc/docsite.json serve -http=localhost:5080",
"build-browser-extension": "pnpm --filter @sourcegraph/browser run build",
"chromatic": "CHROMATIC=true pnpm run _chromatic --storybook-config-dir client/storybook/src --build-script-name=storybook:build",
"_chromatic": "chromatic"
},
"jscpd": {
"gitignore": true,
"ignore": [
"**/__snapshots__",
"**/__fixtures__",
"**/*.svg",
"migrations",
"browser/build",
"ui",
"**/assets"
]
},
"devDependencies": {
"@atlassian/aui": "^7.10.3",
"@axe-core/puppeteer": "^4.4.2",
"@gql2ts/types": "^1.9.0",
"@graphql-codegen/cli": "^2.16.1",
"@graphql-codegen/plugin-helpers": "^5.0.1",
"@graphql-codegen/typescript": "2.8.5",
"@graphql-codegen/typescript-apollo-client-helpers": "^2.2.6",
"@graphql-codegen/typescript-operations": "2.5.10",
"@ianvs/prettier-plugin-sort-imports": "^3.7.1",
"@octokit/rest": "^16.36.0",
"@percy/cli": "^1.24.0",
"@percy/puppeteer": "^2.0.2",
"@pollyjs/adapter": "^5.0.0",
"@pollyjs/core": "^5.1.0",
"@pollyjs/persister-fs": "^5.0.0",
"@remix-run/server-runtime": "^1.17.0",
"@sentry/cli": "^1.74.4",
"@sentry/esbuild-plugin": "^2.7.1",
"@slack/web-api": "^5.15.0",
"@sourcegraph/eslint-config": "0.37.1",
"@sourcegraph/eslint-plugin-sourcegraph": "^1.0.5",
"@sourcegraph/eslint-plugin-wildcard": "workspace:*",
"@sourcegraph/extension-api-stubs": "^1.6.1",
"@sourcegraph/prettierrc": "^3.0.3",
"@sourcegraph/stylelint-config": "^1.4.0",
"@sourcegraph/stylelint-plugin-sourcegraph": "^1.0.1",
"@sourcegraph/tsconfig": "^4.0.1",
"@storybook/addon-a11y": "^7.4.6",
"@storybook/addon-actions": "^7.4.6",
"@storybook/addon-console": "^2.0.0",
"@storybook/addon-controls": "^7.4.6",
"@storybook/addon-designs": "^7.0.5",
"@storybook/addon-links": "^7.4.6",
"@storybook/addon-storysource": "^7.4.6",
"@storybook/addon-toolbars": "^7.4.6",
"@storybook/addons": "^7.4.6",
"@storybook/api": "^7.4.6",
"@storybook/builder-vite": "^7.4.6",
"@storybook/cli": "^7.4.6",
"@storybook/client-api": "^7.4.6",
"@storybook/components": "^7.4.6",
"@storybook/core-common": "^7.4.6",
"@storybook/core-events": "^7.4.6",
"@storybook/react": "^7.4.6",
"@storybook/react-vite": "^7.4.6",
"@storybook/theming": "^7.4.6",
"@storybook/types": "^7.4.6",
"@testing-library/dom": "^8.13.0",
"@testing-library/jest-dom": "^6.1.4",
"@testing-library/react-hooks": "^8.0.0",
"@testing-library/user-event": "^13.5.0",
"@types/bloomfilter": "0.0.0",
"@types/body-parser": "^1.19.2",
"@types/chrome": "0.0.127",
"@types/classnames": "2.2.10",
"@types/command-exists": "1.2.0",
"@types/compression": "1.7.2",
"@types/connect-history-api-fallback": "1.3.4",
"@types/d3-format": "2.0.0",
"@types/d3-scale": "^3.3.0",
"@types/d3-shape": "^1.3.1",
"@types/d3-time-format": "3.0.0",
"@types/d3-voronoi": "^1.1.9",
"@types/dedent": "^0.7.0",
"@types/dompurify": "^3.0.0",
"@types/escape-html": "^1.0.1",
"@types/express": "4.17.11",
"@types/glob": "7.1.3",
"@types/google-spreadsheet": "^3.3.1",
"@types/got": "9.6.11",
"@types/highlight.js": "9.12.4",
"@types/history": "^4.7.11",
"@types/isomorphic-fetch": "^0.0.36",
"@types/js-cookie": "2.2.6",
"@types/js-yaml": "4.0.3",
"@types/jsdom": "12.2.4",
"@types/lodash": "4.14.167",
"@types/lru-cache": "^7.6.1",
"@types/marked": "4.0.3",
"@types/mime-types": "2.1.0",
"@types/minimatch": "^5.1.2",
"@types/mocha": "8.2.0",
"@types/mock-require": "^2.0.1",
"@types/mockdate": "2.0.0",
"@types/mz": "2.7.3",
"@types/node": "20.8.0",
"@types/node-fetch": "2.5.10",
"@types/pollyjs__adapter": "4.3.0",
"@types/pollyjs__core": "4.3.1",
"@types/pollyjs__persister-fs": "2.0.1",
"@types/prettier": "^2.7.2",
"@types/puppeteer": "^5.4.5",
"@types/react": "18.0.8",
"@types/react-calendar": "^3.5.2",
"@types/react-circular-progressbar": "1.0.2",
"@types/react-dom": "18.0.2",
"@types/react-grid-layout": "1.3.2",
"@types/react-resizable": "^3.0.2",
"@types/recharts": "1.8.23",
"@types/resize-observer-browser": "0.1.4",
"@types/rimraf": "^3.0.2",
"@types/semver": "7.3.1",
"@types/shelljs": "0.8.8",
"@types/signale": "1.4.1",
"@types/simmerjs": "0.5.4",
"@types/sinon": "9.0.4",
"@types/stream-json": "^1.7.3",
"@types/uuid": "8.0.1",
"@types/whatwg-url": "^11.0.3",
"@types/yauzl": "^2.9.2",
"@vitejs/plugin-react": "^3.1.0",
"abort-controller": "^3.0.0",
"autoprefixer": "^10.2.1",
"axe-core": "^4.4.1",
"bundlesize2": "^0.0.31",
"chalk": "^4.1.0",
"chokidar-cli": "^2.1.0",
"chromatic": "^10.1.0",
"chrome-webstore-upload-cli": "^1.2.0",
"command-exists": "^1.2.9",
"compression": "^1.7.4",
"concurrently": "^7.6.0",
"connect-history-api-fallback": "^1.6.0",
"cross-env": "^7.0.2",
"dedent": "^0.7.0",
"dompurify": "^3.0.6",
"envalid": "^7.3.1",
"esbuild": "^0.17.14",
"eslint": "^8.52.0",
"eslint-plugin-monorepo": "^0.3.2",
"eslint-plugin-react": "^7.33.2",
"eslint-plugin-storybook": "^0.6.15",
"events": "^3.3.0",
"execa": "^5.0.0",
"expect": "^27.5.1",
"express": "^4.17.1",
"express-static-gzip": "^2.1.1",
"glob": "^7.1.6",
"google-auth-library": "5.7.0",
"googleapis": "^47.0.0",
"googleapis-common": "3.2.0",
"gql2ts": "^1.10.1",
"graphql": "^15.4.0",
"graphql-schema-linter": "^2.0.1",
"happy-dom": "^12.10.1",
"http-proxy-middleware": "^2.0.6",
"identity-obj-proxy": "^3.0.0",
"jsdom": "^22.1.0",
"json-schema-ref-parser": "^9.0.6",
"json-schema-to-typescript": "^10.1.3",
"latest-version": "^5.1.0",
"libhoney": "^3.1.1",
"license-checker": "^25.0.1",
"message-port-polyfill": "^0.2.0",
"mime-types": "^2.1.28",
"mocha": "^8.3.2",
"mock-require": "^3.0.3",
"mockdate": "^3.0.2",
"mz": "^2.7.0",
"node-fetch": "^2.6.7",
"nodemon": "^2.0.20",
"octokit": "^2.0.7",
"open": "^7.0.4",
"p-retry": "^4.2.0",
"p-timeout": "^4.1.0",
"postcss-cli": "^10.1.0",
"postcss-custom-media": "^8.0.0",
"postcss-focus-visible": "^5.0.0",
"prettier": "2.8.1",
"prettier-plugin-svelte": "^2.9.0",
"punycode": "2.1.1",
"puppeteer": "^13.5.1",
"regenerator-runtime": "^0.13.7",
"resolve-bin": "^1.0.1",
"rimraf": "^3.0.2",
"sass": "^1.32.4",
"shelljs": "^0.8.4",
"signale": "^1.4.0",
"simmerjs": "^0.5.6",
"sinon": "^9.0.2",
"sourcegraph": "workspace:*",
"storybook-dark-mode": "^3.0.1",
"stream-browserify": "^3.0.0",
"string-width": "^4.2.0",
"strip-ansi": "^6.0.1",
"stylelint": "^14.3.0",
"term-size": "^2.2.0",
"text-table": "^0.2.0",
"ts-dedent": "^2.2.0",
"ts-node": "^10.7.0",
"typed-scss-modules": "^4.1.1",
"typescript": "^5.0.2",
"utc-version": "^2.0.2",
"vite": "^4.1.4",
"vite-plugin-turbosnap": "^1.0.3",
"vitest": "1.0.0-beta.4",
"vitest-fetch-mock": "^0.2.2",
"vsce": "^2.7.0",
"wildcard-mock-link": "^2.0.1",
"yaml": "^2.2.1",
"yauzl": "^2.10.0"
},
"dependencies": {
"@apollo/client": "^3.8.0-alpha.7",
"@codemirror/autocomplete": "^6.1.0",
"@codemirror/commands": "^6.0.1",
"@codemirror/lang-json": "^6.0.0",
"@codemirror/lang-markdown": "^6.0.0",
"@codemirror/language": "^6.2.0",
"@codemirror/legacy-modes": "^6.3.1",
"@codemirror/lint": "^6.0.0",
"@codemirror/search": "^6.0.1",
"@codemirror/state": "^6.2.0",
"@codemirror/view": "^6.7.2",
"@graphiql/react": "^0.10.0",
"@lezer/common": "^1.0.0",
"@lezer/highlight": "^1.0.0",
"@mdi/js": "7.1.96",
"@microsoft/fast-web-utilities": "^6.0.0",
"@microsoft/fetch-event-source": "^2.0.1",
"@opencodegraph/client": "^0.0.1",
"@opencodegraph/codemirror-extension": "^0.0.1",
"@opentelemetry/api": "^1.4.0",
"@opentelemetry/context-zone": "^1.9.1",
"@opentelemetry/core": "1.9.1",
"@opentelemetry/exporter-trace-otlp-http": "^0.35.0",
"@opentelemetry/instrumentation": "^0.35.1",
"@opentelemetry/instrumentation-fetch": "^0.35.1",
"@opentelemetry/resources": "1.9.1",
"@opentelemetry/sdk-trace-base": "1.9.1",
"@opentelemetry/sdk-trace-web": "^1.9.1",
"@opentelemetry/semantic-conventions": "^1.9.1",
"@reach/accordion": "^0.16.1",
"@reach/auto-id": "^0.16.0",
"@reach/combobox": "^0.16.5",
"@reach/dialog": "^0.16.2",
"@reach/menu-button": "^0.16.2",
"@reach/tabs": "^0.16.4",
"@reach/visually-hidden": "^0.16.0",
"@react-aria/live-announcer": "^3.1.0",
"@sentry/browser": "^7.8.1",
"@sourcegraph/extension-api-classes": "^1.1.0",
"@testing-library/react": "^13.4.0",
"@visx/annotation": "^2.10.0",
"@visx/axis": "^2.11.1",
"@visx/event": "2.6.0",
"@visx/glyph": "^2.10.0",
"@visx/grid": "^2.10.0",
"@visx/group": "^2.10.0",
"@visx/responsive": "^2.10.0",
"@visx/scale": "^2.2.2",
"@visx/shape": "^2.11.1",
"@visx/text": "2.10.0",
"@visx/voronoi": "^2.10.0",
"agent-base": "6.0.2",
"ajv": "^8.6.3",
"ajv-formats": "^2.1.1",
"apollo3-cache-persist": "^0.12.1",
"bloomfilter": "^0.0.18",
"buffer": "^6.0.3",
"classnames": "^2.2.6",
"comlink": "^4.3.0",
"copy-to-clipboard": "^3.3.1",
"core-js": "^3.8.2",
"d3-format": "^2.0.0",
"d3-scale": "^3.3.0",
"d3-shape": "^1.2.0",
"d3-time-format": "^3.0.0",
"d3-voronoi": "^1.1.2",
"date-fns": "^2.16.1",
"delay": "^4.4.1",
"detect-indent": "^6.1.0",
"downshift": "^3.4.8",
"escape-html": "^1.0.3",
"eventsource": "1.1.1",
"fast-json-stable-stringify": "^2.0.0",
"focus-visible": "^5.2.0",
"fzf": "^0.5.1",
"got": "^11.5.2",
"graphiql": "^1.11.5",
"handlebars": "^4.7.7",
"highlight.js": "^10.5.0",
"highlightjs-graphql": "^1.0.2",
"history": "4.5.1",
"http-proxy-agent": "^5.0.0",
"http-status-codes": "^2.1.4",
"https-browserify": "^1.0.0",
"https-proxy-agent": "^5.0.1",
"is-absolute-url": "^3.0.3",
"isomorphic-fetch": "^3.0.0",
"iterare": "^1.2.1",
"js-base64": "^3.7.2",
"js-cookie": "^2.2.1",
"js-yaml": "^4.1.0",
"jsonc-parser": "^3.0.0",
"linguist-languages": "^7.14.0",
"linkifyjs": "^4.1.0",
"lit-html": "^2.7.2",
"lodash": "^4.17.20",
"lru-cache": "^7.8.0",
"marked": "4.0.16",
"mdi-react": "^8.1.0",
"minimatch": "^3.0.4",
"mockdate": "^3.0.2",
"monaco-editor": "^0.24.0",
"monaco-yaml": "^3.2.1",
"nice-ticks": "^1.0.1",
"open-color": "^1.8.0",
"ordinal": "^1.0.3",
"original": "^1.0.0",
"path-browserify": "^1.0.1",
"postcss-inset": "^1.0.0",
"pretty-bytes": "^5.3.0",
"process": "^0.11.10",
"prop-types": "^15.7.2",
"react": "18.1.0",
"react-calendar": "^3.7.0",
"react-circular-progressbar": "^2.0.3",
"react-dom": "18.1.0",
"react-focus-lock": "^2.7.1",
"react-grid-layout": "1.3.4",
"react-icons": "^4.12.0",
"react-resizable": "^3.0.4",
"react-router-dom": "^6.8.1",
"react-spring": "^9.4.2",
"react-sticky-box": "1.0.2",
"react-visibility-sensor": "^5.1.1",
"recharts": "^1.8.5",
"regexpp": "^3.1.0",
"resize-observer-polyfill": "^1.5.1",
"rxjs": "^6.6.3",
"semver": "^7.3.2",
"stream-http": "^3.2.0",
"stream-json": "^1.7.5",
"tagged-template-noop": "^2.1.1",
"ts-key-enum": "^2.0.7",
"tslib": "^2.1.0",
"url": "^0.11.0",
"use-callback-ref": "^1.2.5",
"use-debounce": "^8.0.1",
"use-deep-compare-effect": "^1.6.1",
"use-resize-observer": "^9.0.2",
"util": "^0.12.5",
"utility-types": "^3.10.0",
"uuid": "^8.3.0",
"webext-domain-permission-toggle": "^1.0.1",
"webextension-polyfill": "^0.6.0",
"whatwg-url": "^14.0.0",
"yaml-ast-parser": "^0.0.43",
"zustand": "^3.6.9"
},
"packageManager": "pnpm@8.9.2",
"pnpm": {
"packageExtensions": {
"hnswlib-node": {
"dependencies": {
"node-gyp": "*"
}
},
"deasync": {
"dependencies": {
"node-gyp": "*"
}
},
"cpu-features": {
"dependencies": {
"node-gyp": "*"
}
},
"@percy/sdk-utils": {
"dependencies": {
"ws": "*"
}
},
"@graphql-codegen/cli@5": {
"peerDependencies": {
"@graphql-codegen/typescript": "*",
"@graphql-codegen/typescript-operations": "*",
"@graphql-codegen/near-operation-file-preset": "*",
"@graphql-codegen/typed-document-node": "*"
}
}
}
},
"resolutions": {
"browserify-zlib": "0.2.0",
"history": "4.5.1",
"cssnano": "4.1.10",
"tslib": "2.1.0"
}
}