@quilted/create 0.3.1 → 0.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/build/esm/_virtual/index7.mjs +2 -2
  3. package/build/esm/_virtual/index8.mjs +2 -2
  4. package/build/esm/node_modules/.pnpm/dir-glob@3.0.1/node_modules/dir-glob/index.mjs +1 -1
  5. package/build/esm/node_modules/.pnpm/fast-glob@3.3.3/node_modules/fast-glob/out/utils/index.mjs +1 -1
  6. package/build/esm/node_modules/.pnpm/prompts@2.4.2/node_modules/prompts/dist/prompts.mjs +1 -1
  7. package/build/esm/node_modules/.pnpm/prompts@2.4.2/node_modules/prompts/lib/prompts.mjs +1 -1
  8. package/build/esnext/node_modules/.pnpm/@nodelib_fs.stat@2.0.5/node_modules/@nodelib/fs.stat/out/index.esnext +1 -1
  9. package/build/esnext/node_modules/.pnpm/@nodelib_fs.stat@2.0.5/node_modules/@nodelib/fs.stat/out/providers/async.esnext +1 -1
  10. package/build/esnext/node_modules/.pnpm/@nodelib_fs.stat@2.0.5/node_modules/@nodelib/fs.stat/out/providers/sync.esnext +1 -1
  11. package/build/esnext/node_modules/.pnpm/@nodelib_fs.stat@2.0.5/node_modules/@nodelib/fs.stat/out/settings.esnext +1 -1
  12. package/build/esnext/node_modules/.pnpm/@nodelib_fs.walk@1.2.8/node_modules/@nodelib/fs.walk/out/index.esnext +1 -1
  13. package/build/esnext/node_modules/.pnpm/@nodelib_fs.walk@1.2.8/node_modules/@nodelib/fs.walk/out/providers/async.esnext +1 -1
  14. package/build/esnext/node_modules/.pnpm/@nodelib_fs.walk@1.2.8/node_modules/@nodelib/fs.walk/out/providers/sync.esnext +1 -1
  15. package/build/esnext/node_modules/.pnpm/@nodelib_fs.walk@1.2.8/node_modules/@nodelib/fs.walk/out/settings.esnext +1 -1
  16. package/build/esnext/node_modules/.pnpm/fast-glob@3.3.3/node_modules/fast-glob/out/readers/stream.esnext +1 -1
  17. package/build/esnext/node_modules/.pnpm/fast-glob@3.3.3/node_modules/fast-glob/out/utils/stream.esnext +1 -1
  18. package/build/esnext/node_modules/.pnpm/prompts@2.4.2/node_modules/prompts/dist/prompts.esnext +1 -1
  19. package/build/esnext/node_modules/.pnpm/prompts@2.4.2/node_modules/prompts/lib/prompts.esnext +1 -1
  20. package/package.json +1 -1
  21. package/templates/app-basic/App.tsx +8 -3
  22. package/templates/app-basic/browser.css +10 -0
  23. package/templates/app-basic/browser.tsx +8 -12
  24. package/templates/app-basic/context/browser.ts +10 -0
  25. package/templates/app-basic/context/navigation.ts +17 -0
  26. package/templates/app-basic/{shared/context.ts → context/preact.ts} +1 -1
  27. package/templates/app-basic/context/server.ts +10 -0
  28. package/templates/app-basic/context/types.ts +5 -0
  29. package/templates/app-basic/foundation/frame/Frame.module.css +0 -11
  30. package/templates/app-basic/server.tsx +5 -14
  31. package/templates/app-basic/tests/render/render.tsx +6 -3
  32. package/templates/app-basic/tests/render/types.ts +2 -2
  33. package/templates/app-basic/tsconfig.json +2 -4
  34. package/templates/app-graphql/App.tsx +4 -3
  35. package/templates/app-graphql/browser.css +10 -0
  36. package/templates/app-graphql/browser.tsx +9 -23
  37. package/templates/app-graphql/context/browser.ts +21 -0
  38. package/templates/app-graphql/context/navigation.ts +17 -0
  39. package/templates/{app-trpc/shared/context.ts → app-graphql/context/preact.ts} +1 -1
  40. package/templates/app-graphql/context/server.ts +23 -0
  41. package/templates/app-graphql/context/types.ts +10 -0
  42. package/templates/app-graphql/server.tsx +4 -24
  43. package/templates/app-graphql/tests/render/render.tsx +11 -8
  44. package/templates/app-graphql/tests/render/types.ts +9 -4
  45. package/templates/app-graphql/tsconfig.json +1 -1
  46. package/templates/app-trpc/App.tsx +5 -7
  47. package/templates/app-trpc/browser.css +10 -0
  48. package/templates/app-trpc/browser.tsx +9 -23
  49. package/templates/app-trpc/context/browser.ts +20 -0
  50. package/templates/app-trpc/context/navigation.ts +17 -0
  51. package/templates/{app-graphql/shared/context.ts → app-trpc/context/preact.ts} +1 -1
  52. package/templates/app-trpc/context/server.ts +18 -0
  53. package/templates/app-trpc/context/trpc.ts +6 -0
  54. package/templates/app-trpc/context/types.ts +11 -0
  55. package/templates/app-trpc/features/home/Home.tsx +1 -1
  56. package/templates/app-trpc/server.tsx +4 -19
  57. package/templates/app-trpc/tests/render/render.tsx +9 -4
  58. package/templates/app-trpc/tests/render/types.ts +2 -2
  59. package/templates/app-trpc/tsconfig.json +1 -1
  60. package/templates/app-basic/shared/navigation.ts +0 -15
  61. package/templates/app-graphql/shared/graphql.ts +0 -22
  62. package/templates/app-graphql/shared/navigation.ts +0 -15
  63. package/templates/app-trpc/shared/navigation.ts +0 -15
  64. package/templates/app-trpc/shared/trpc.ts +0 -18
package/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # @quilted/create
2
2
 
3
+ ## 0.3.2
4
+
5
+ ### Patch Changes
6
+
7
+ - [`be4e753`](https://github.com/lemonmade/quilt/commit/be4e7532de2bdda83302c2eb8bc2a0a09aeae07e) Thanks [@lemonmade](https://github.com/lemonmade)! - Refactor app template context structure: replace `shared/` directory with `context/` directory
8
+
9
+ The `shared/` directory, which used TypeScript declaration merging to build up the `AppContext` interface across multiple files, has been replaced with a `context/` directory that defines the full interface explicitly in a single `types.ts` file. This makes the shape of the application context immediately visible without needing to trace module augmentations.
10
+
11
+ The new structure separates each concern into its own file: `types.ts` owns the interface, `navigation.ts` provides the router and route helpers, `preact.ts` holds the Preact context binding, `browser.ts` exports `BrowserAppContext`, and `server.ts` exports `ServerAppContext`. The context classes have been extracted from `browser.tsx` and `server.tsx` into these dedicated files, keeping the entry points lean.
12
+
13
+ Navigation is now accessed as `context.navigation.router` instead of `context.router`, grouping router state under a `navigation` namespace. A `browser.css` file has also been added to each app template for global CSS resets.
14
+
3
15
  ## 0.3.1
4
16
 
5
17
  ### Patch Changes
@@ -1,3 +1,3 @@
1
- var utils = {};
1
+ var dirGlob = {exports: {}};
2
2
 
3
- export { utils as __exports };
3
+ export { dirGlob as __module };
@@ -1,3 +1,3 @@
1
- var dirGlob = {exports: {}};
1
+ var utils = {};
2
2
 
3
- export { dirGlob as __module };
3
+ export { utils as __exports };
@@ -1,4 +1,4 @@
1
- import { __module as dirGlob } from '../../../../../_virtual/index8.mjs';
1
+ import { __module as dirGlob } from '../../../../../_virtual/index7.mjs';
2
2
  import path__default from 'node:path';
3
3
  import { __require as requirePathType } from '../../../path-type@4.0.0/node_modules/path-type/index.mjs';
4
4
 
@@ -1,4 +1,4 @@
1
- import { __exports as utils } from '../../../../../../../_virtual/index7.mjs';
1
+ import { __exports as utils } from '../../../../../../../_virtual/index8.mjs';
2
2
  import { __require as requireArray } from './array.mjs';
3
3
  import { __require as requireErrno } from './errno.mjs';
4
4
  import { __require as requireFs } from './fs.mjs';
@@ -1,4 +1,4 @@
1
- import { __exports as prompts } from '../../../../../../_virtual/prompts2.mjs';
1
+ import { __exports as prompts } from '../../../../../../_virtual/prompts.mjs';
2
2
  import { __require as requireElements } from './elements/index.mjs';
3
3
 
4
4
  var hasRequiredPrompts;
@@ -1,4 +1,4 @@
1
- import { __exports as prompts } from '../../../../../../_virtual/prompts.mjs';
1
+ import { __exports as prompts } from '../../../../../../_virtual/prompts2.mjs';
2
2
  import { __require as requireElements } from './elements/index.mjs';
3
3
 
4
4
  var hasRequiredPrompts;
@@ -1,4 +1,4 @@
1
- import { __exports as out } from '../../../../../../../_virtual/index11.esnext';
1
+ import { __exports as out } from '../../../../../../../_virtual/index10.esnext';
2
2
  import { __require as requireAsync } from './providers/async.esnext';
3
3
  import { __require as requireSync } from './providers/sync.esnext';
4
4
  import { __require as requireSettings } from './settings.esnext';
@@ -1,4 +1,4 @@
1
- import { __exports as async } from '../../../../../../../../_virtual/async4.esnext';
1
+ import { __exports as async } from '../../../../../../../../_virtual/async3.esnext';
2
2
 
3
3
  var hasRequiredAsync;
4
4
  function requireAsync() {
@@ -1,4 +1,4 @@
1
- import { __exports as sync } from '../../../../../../../../_virtual/sync4.esnext';
1
+ import { __exports as sync } from '../../../../../../../../_virtual/sync3.esnext';
2
2
 
3
3
  var hasRequiredSync;
4
4
  function requireSync() {
@@ -1,4 +1,4 @@
1
- import { __exports as settings } from '../../../../../../../_virtual/settings3.esnext';
1
+ import { __exports as settings } from '../../../../../../../_virtual/settings2.esnext';
2
2
  import { __require as requireFs } from './adapters/fs.esnext';
3
3
 
4
4
  var hasRequiredSettings;
@@ -1,4 +1,4 @@
1
- import { __exports as out } from '../../../../../../../_virtual/index10.esnext';
1
+ import { __exports as out } from '../../../../../../../_virtual/index11.esnext';
2
2
  import { __require as requireAsync } from './providers/async.esnext';
3
3
  import { __require as requireStream } from './providers/stream.esnext';
4
4
  import { __require as requireSync } from './providers/sync.esnext';
@@ -1,4 +1,4 @@
1
- import { __exports as async } from '../../../../../../../../_virtual/async3.esnext';
1
+ import { __exports as async } from '../../../../../../../../_virtual/async4.esnext';
2
2
  import { __require as requireAsync$1 } from '../readers/async.esnext';
3
3
 
4
4
  var hasRequiredAsync;
@@ -1,4 +1,4 @@
1
- import { __exports as sync } from '../../../../../../../../_virtual/sync3.esnext';
1
+ import { __exports as sync } from '../../../../../../../../_virtual/sync4.esnext';
2
2
  import { __require as requireSync$1 } from '../readers/sync.esnext';
3
3
 
4
4
  var hasRequiredSync;
@@ -1,4 +1,4 @@
1
- import { __exports as settings } from '../../../../../../../_virtual/settings2.esnext';
1
+ import { __exports as settings } from '../../../../../../../_virtual/settings3.esnext';
2
2
  import path__default from 'node:path';
3
3
  import { __require as requireOut } from '../../../../../@nodelib_fs.scandir@2.1.5/node_modules/@nodelib/fs.scandir/out/index.esnext';
4
4
 
@@ -1,4 +1,4 @@
1
- import { __exports as stream } from '../../../../../../../_virtual/stream2.esnext';
1
+ import { __exports as stream } from '../../../../../../../_virtual/stream3.esnext';
2
2
  import require$$0 from 'node:stream';
3
3
  import { __require as requireOut } from '../../../../../@nodelib_fs.stat@2.0.5/node_modules/@nodelib/fs.stat/out/index.esnext';
4
4
  import { __require as requireOut$1 } from '../../../../../@nodelib_fs.walk@1.2.8/node_modules/@nodelib/fs.walk/out/index.esnext';
@@ -1,4 +1,4 @@
1
- import { __exports as stream } from '../../../../../../../_virtual/stream3.esnext';
1
+ import { __exports as stream } from '../../../../../../../_virtual/stream2.esnext';
2
2
  import { __require as requireMerge2 } from '../../../../../merge2@1.4.1/node_modules/merge2/index.esnext';
3
3
 
4
4
  var hasRequiredStream;
@@ -1,4 +1,4 @@
1
- import { __exports as prompts } from '../../../../../../_virtual/prompts2.esnext';
1
+ import { __exports as prompts } from '../../../../../../_virtual/prompts.esnext';
2
2
  import { __require as requireElements } from './elements/index.esnext';
3
3
 
4
4
  var hasRequiredPrompts;
@@ -1,4 +1,4 @@
1
- import { __exports as prompts } from '../../../../../../_virtual/prompts.esnext';
1
+ import { __exports as prompts } from '../../../../../../_virtual/prompts2.esnext';
2
2
  import { __require as requireElements } from './elements/index.esnext';
3
3
 
4
4
  var hasRequiredPrompts;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@quilted/create",
3
3
  "type": "module",
4
- "version": "0.3.1",
4
+ "version": "0.3.2",
5
5
  "license": "MIT",
6
6
  "repository": {
7
7
  "type": "git",
@@ -7,8 +7,9 @@ import {Frame} from './foundation/frame.ts';
7
7
 
8
8
  import {Home} from './features/home.ts';
9
9
 
10
- import {AppContextPreact, type AppContext} from './shared/context.ts';
11
- import {routeWithAppContext} from './shared/navigation.ts';
10
+ import type {AppContext} from './context/types.ts';
11
+ import {AppContextPreact} from './context/preact.ts';
12
+ import {routeWithAppContext} from './context/navigation.ts';
12
13
 
13
14
  export interface AppProps {
14
15
  context: AppContext;
@@ -38,7 +39,11 @@ export function App({context}: AppProps) {
38
39
  <AppContextPreact.Provider value={context}>
39
40
  <Localization>
40
41
  <Head />
41
- <Navigation router={context.router} routes={routes} context={context} />
42
+ <Navigation
43
+ router={context.navigation.router}
44
+ routes={routes}
45
+ context={context}
46
+ />
42
47
  </Localization>
43
48
  </AppContextPreact.Provider>
44
49
  );
@@ -0,0 +1,10 @@
1
+ *,
2
+ *::before,
3
+ *::after {
4
+ box-sizing: border-box;
5
+ }
6
+
7
+ html,
8
+ body {
9
+ margin: 0;
10
+ }
@@ -1,18 +1,11 @@
1
+ import './browser.css';
2
+
1
3
  import type {ComponentChild} from 'preact';
2
4
  import {hydrate} from '@quilted/quilt/browser';
3
- import {Router} from '@quilted/quilt/navigation';
4
5
 
5
- import type {AppContext} from '~/shared/context.ts';
6
+ import {BrowserAppContext} from '~/context/browser.ts';
6
7
  import {App} from './App.tsx';
7
8
 
8
- class BrowserAppContext implements AppContext {
9
- readonly router: Router;
10
-
11
- constructor() {
12
- this.router = new Router();
13
- }
14
- }
15
-
16
9
  class BrowserApp {
17
10
  /**
18
11
  * The app’s globally-available context.
@@ -42,8 +35,11 @@ class BrowserApp {
42
35
  writable: true,
43
36
  });
44
37
  }
38
+
39
+ hydrate() {
40
+ hydrate(this.rendered);
41
+ }
45
42
  }
46
43
 
47
44
  const app = new BrowserApp();
48
-
49
- hydrate(app.rendered);
45
+ app.hydrate();
@@ -0,0 +1,10 @@
1
+ import type {AppContext} from './types.ts';
2
+ import {NavigationForApp} from './navigation.ts';
3
+
4
+ export class BrowserAppContext implements AppContext {
5
+ readonly navigation: NavigationForApp;
6
+
7
+ constructor() {
8
+ this.navigation = new NavigationForApp();
9
+ }
10
+ }
@@ -0,0 +1,17 @@
1
+ import {createContextRouteFunction, Router} from '@quilted/quilt/navigation';
2
+
3
+ import type {AppContext} from './types.ts';
4
+
5
+ export interface Navigation {
6
+ readonly router: Router;
7
+ }
8
+
9
+ export class NavigationForApp implements Navigation {
10
+ readonly router: Router;
11
+
12
+ constructor(url?: string | URL) {
13
+ this.router = new Router(url);
14
+ }
15
+ }
16
+
17
+ export const routeWithAppContext = createContextRouteFunction<AppContext>();
@@ -1,6 +1,6 @@
1
1
  import {createOptionalContext} from '@quilted/quilt/context';
2
2
 
3
- export interface AppContext {}
3
+ import type {AppContext} from './types.ts';
4
4
 
5
5
  export const AppContextPreact = createOptionalContext<AppContext>();
6
6
  export const useAppContext = AppContextPreact.use;
@@ -0,0 +1,10 @@
1
+ import type {AppContext} from './types.ts';
2
+ import {NavigationForApp} from './navigation.ts';
3
+
4
+ export class ServerAppContext implements AppContext {
5
+ readonly navigation: NavigationForApp;
6
+
7
+ constructor(request: Request) {
8
+ this.navigation = new NavigationForApp(request.url);
9
+ }
10
+ }
@@ -0,0 +1,5 @@
1
+ import type {Navigation} from './navigation.ts';
2
+
3
+ export interface AppContext {
4
+ readonly navigation: Navigation;
5
+ }
@@ -1,14 +1,3 @@
1
- *,
2
- *::before,
3
- *::after {
4
- box-sizing: border-box;
5
- }
6
-
7
- html,
8
- body {
9
- margin: 0;
10
- }
11
-
12
1
  .Frame {
13
2
  padding: 1rem;
14
3
  }
@@ -6,30 +6,21 @@ import {
6
6
  PermissionsPolicyHeader,
7
7
  StrictTransportSecurityHeader,
8
8
  } from '@quilted/quilt/server';
9
- import {Router} from '@quilted/quilt/navigation';
10
-
11
9
  import Env from 'quilt:module/env';
12
10
  import {BrowserAssets} from 'quilt:module/assets';
13
11
 
14
- import type {AppContext} from '~/shared/context.ts';
15
-
16
- import {App} from './App.tsx';
17
-
18
12
  const app = new Hono();
19
13
  const assets = new BrowserAssets();
20
14
 
21
- class ServerAppContext implements AppContext {
22
- readonly router: Router;
23
-
24
- constructor(request: Request) {
25
- this.router = new Router(request.url);
26
- }
27
- }
28
-
29
15
  // For all GET requests, render our Preact application.
30
16
  app.get('*', async (c) => {
31
17
  const request = c.req.raw;
32
18
 
19
+ const [{App}, {ServerAppContext}] = await Promise.all([
20
+ import('./App.tsx'),
21
+ import('./context/server.ts'),
22
+ ]);
23
+
33
24
  const context = new ServerAppContext(request);
34
25
 
35
26
  const isHttps = request.url.startsWith('https://');
@@ -6,7 +6,7 @@ import {
6
6
  import {Navigation, TestRouter} from '@quilted/quilt/navigation/testing';
7
7
  import {Localization} from '@quilted/quilt/localize';
8
8
 
9
- import {AppContextPreact} from '~/shared/context.ts';
9
+ import {AppContextPreact} from '~/context/preact.ts';
10
10
 
11
11
  import {RenderOptions, RenderContext, RenderActions} from './types.ts';
12
12
 
@@ -24,11 +24,14 @@ export const renderApp = createRender<
24
24
  // authors on the `root.context` property. Context is used to share data between your
25
25
  // React tree and your test code, and is ideal for mocking out global context providers.
26
26
  context({router = new TestRouter(), browser = new BrowserTestMock()}) {
27
- return {router, browser};
27
+ return {navigation: {router}, browser};
28
28
  },
29
29
  // Render all of our app-wide context providers around each component under test.
30
30
  render(element, context, {locale = 'en'}) {
31
- const {router, browser} = context;
31
+ const {
32
+ navigation: {router},
33
+ browser,
34
+ } = context;
32
35
 
33
36
  return (
34
37
  <AppContextPreact.Provider value={context}>
@@ -1,7 +1,7 @@
1
1
  import type {TestRouter} from '@quilted/quilt/navigation/testing';
2
2
  import type {BrowserTestMock} from '@quilted/quilt/browser/testing';
3
3
 
4
- import type {AppContext} from '~/shared/context.ts';
4
+ import type {AppContext} from '~/context/types.ts';
5
5
 
6
6
  export interface RenderOptions {
7
7
  /**
@@ -27,7 +27,7 @@ export interface RenderContext extends AppContext {
27
27
  /**
28
28
  * The router used for this component test.
29
29
  */
30
- readonly router: TestRouter;
30
+ readonly navigation: {router: TestRouter};
31
31
 
32
32
  /**
33
33
  * The browser environment for this component test.
@@ -3,10 +3,8 @@
3
3
  "compilerOptions": {
4
4
  "jsxImportSource": "preact",
5
5
  "paths": {
6
- "~/shared/*": ["./shared/*"],
7
- "~/tests/*": ["./tests/*"],
8
- "react": ["./node_modules/preact/compat"],
9
- "react-dom": ["./node_modules/preact/compat"]
6
+ "~/context/*": ["./context/*"],
7
+ "~/tests/*": ["./tests/*"]
10
8
  }
11
9
  },
12
10
  "include": ["**/*"],
@@ -8,8 +8,9 @@ import {Frame} from './foundation/frame.ts';
8
8
 
9
9
  import {Home, homeQuery} from './features/home.ts';
10
10
 
11
- import {AppContextPreact, type AppContext} from './shared/context.ts';
12
- import {routeWithAppContext} from './shared/navigation.ts';
11
+ import type {AppContext} from './context/types.ts';
12
+ import {AppContextPreact} from './context/preact.ts';
13
+ import {routeWithAppContext} from './context/navigation.ts';
13
14
 
14
15
  export interface AppProps {
15
16
  context: AppContext;
@@ -44,7 +45,7 @@ export function App({context}: AppProps) {
44
45
  <Localization>
45
46
  <Head />
46
47
  <Navigation
47
- router={context.router}
48
+ router={context.navigation.router}
48
49
  routes={routes}
49
50
  context={context}
50
51
  />
@@ -0,0 +1,10 @@
1
+ *,
2
+ *::before,
3
+ *::after {
4
+ box-sizing: border-box;
5
+ }
6
+
7
+ html,
8
+ body {
9
+ margin: 0;
10
+ }
@@ -1,29 +1,12 @@
1
+ import './browser.css';
2
+
1
3
  import type {ComponentChild} from 'preact';
2
4
  import {hydrate} from '@quilted/quilt/browser';
3
- import {Router} from '@quilted/quilt/navigation';
4
- import {createGraphQLFetch, GraphQLCache} from '@quilted/quilt/graphql';
5
5
 
6
- import type {AppContext} from '~/shared/context.ts';
6
+ import {BrowserAppContext} from '~/context/browser.ts';
7
7
 
8
8
  import {App} from './App.tsx';
9
9
 
10
- class BrowserAppContext implements AppContext {
11
- readonly router: Router;
12
- readonly graphql: AppContext['graphql'];
13
-
14
- constructor() {
15
- this.router = new Router();
16
-
17
- const graphQLFetch = createGraphQLFetch({url: '/api/graphql'});
18
- const graphQLCache = new GraphQLCache({fetch: graphQLFetch});
19
-
20
- this.graphql = {
21
- fetch: graphQLFetch,
22
- cache: graphQLCache,
23
- };
24
- }
25
- }
26
-
27
10
  class BrowserApp {
28
11
  /**
29
12
  * The app's globally-available context.
@@ -44,7 +27,7 @@ class BrowserApp {
44
27
  // @example
45
28
  // ```js
46
29
  // // Log the current URL
47
- // console.log(globalThis.app.context.router.currentRequest.url);
30
+ // console.log(globalThis.app.context.navigation.router.currentRequest.url);
48
31
  // ```
49
32
  Object.defineProperty(globalThis, 'app', {
50
33
  value: this,
@@ -53,8 +36,11 @@ class BrowserApp {
53
36
  writable: true,
54
37
  });
55
38
  }
39
+
40
+ hydrate() {
41
+ hydrate(this.rendered);
42
+ }
56
43
  }
57
44
 
58
45
  const app = new BrowserApp();
59
-
60
- hydrate(app.rendered);
46
+ app.hydrate();
@@ -0,0 +1,21 @@
1
+ import {createGraphQLFetch, GraphQLCache} from '@quilted/quilt/graphql';
2
+
3
+ import type {AppContext} from './types.ts';
4
+ import {NavigationForApp} from './navigation.ts';
5
+
6
+ export class BrowserAppContext implements AppContext {
7
+ readonly navigation: NavigationForApp;
8
+ readonly graphql: AppContext['graphql'];
9
+
10
+ constructor() {
11
+ this.navigation = new NavigationForApp();
12
+
13
+ const graphQLFetch = createGraphQLFetch({url: '/api/graphql'});
14
+ const graphQLCache = new GraphQLCache({fetch: graphQLFetch});
15
+
16
+ this.graphql = {
17
+ fetch: graphQLFetch,
18
+ cache: graphQLCache,
19
+ };
20
+ }
21
+ }
@@ -0,0 +1,17 @@
1
+ import {createContextRouteFunction, Router} from '@quilted/quilt/navigation';
2
+
3
+ import type {AppContext} from './types.ts';
4
+
5
+ export interface Navigation {
6
+ readonly router: Router;
7
+ }
8
+
9
+ export class NavigationForApp implements Navigation {
10
+ readonly router: Router;
11
+
12
+ constructor(url?: string | URL) {
13
+ this.router = new Router(url);
14
+ }
15
+ }
16
+
17
+ export const routeWithAppContext = createContextRouteFunction<AppContext>();
@@ -1,6 +1,6 @@
1
1
  import {createOptionalContext} from '@quilted/quilt/context';
2
2
 
3
- export interface AppContext {}
3
+ import type {AppContext} from './types.ts';
4
4
 
5
5
  export const AppContextPreact = createOptionalContext<AppContext>();
6
6
  export const useAppContext = AppContextPreact.use;
@@ -0,0 +1,23 @@
1
+ import {GraphQLCache} from '@quilted/quilt/graphql';
2
+
3
+ import type {AppContext} from './types.ts';
4
+ import {NavigationForApp} from './navigation.ts';
5
+
6
+ export class ServerAppContext implements AppContext {
7
+ readonly navigation: NavigationForApp;
8
+ readonly graphql: AppContext['graphql'];
9
+
10
+ constructor(request: Request) {
11
+ this.navigation = new NavigationForApp(request.url);
12
+
13
+ const graphQLFetch: AppContext['graphql']['fetch'] = async (...args) => {
14
+ const {performGraphQLOperation} = await import('../server/graphql.ts');
15
+ return performGraphQLOperation(...args);
16
+ };
17
+
18
+ this.graphql = {
19
+ fetch: graphQLFetch,
20
+ cache: new GraphQLCache({fetch: graphQLFetch}),
21
+ };
22
+ }
23
+ }
@@ -0,0 +1,10 @@
1
+ import type {Navigation} from './navigation.ts';
2
+ import type {GraphQLFetch, GraphQLCache} from '@quilted/quilt/graphql';
3
+
4
+ export interface AppContext {
5
+ readonly navigation: Navigation;
6
+ readonly graphql: {
7
+ readonly fetch: GraphQLFetch;
8
+ readonly cache: GraphQLCache;
9
+ };
10
+ }
@@ -1,5 +1,4 @@
1
1
  import {Hono} from 'hono';
2
- import {Router} from '@quilted/quilt/navigation';
3
2
  import {
4
3
  renderAppToHTMLResponse,
5
4
  CacheControlHeader,
@@ -7,35 +6,13 @@ import {
7
6
  PermissionsPolicyHeader,
8
7
  StrictTransportSecurityHeader,
9
8
  } from '@quilted/quilt/server';
10
- import {GraphQLCache} from '@quilted/quilt/graphql';
11
9
 
12
10
  import Env from 'quilt:module/env';
13
11
  import {BrowserAssets} from 'quilt:module/assets';
14
12
 
15
- import type {AppContext} from '~/shared/context.ts';
16
-
17
13
  const app = new Hono();
18
14
  const assets = new BrowserAssets();
19
15
 
20
- class ServerAppContext implements AppContext {
21
- readonly router: Router;
22
- readonly graphql: AppContext['graphql'];
23
-
24
- constructor(request: Request) {
25
- this.router = new Router(request.url);
26
-
27
- const graphQLFetch: AppContext['graphql']['fetch'] = async (...args) => {
28
- const {performGraphQLOperation} = await import('./server/graphql.ts');
29
- return performGraphQLOperation(...args);
30
- };
31
-
32
- this.graphql = {
33
- fetch: graphQLFetch,
34
- cache: new GraphQLCache({fetch: graphQLFetch}),
35
- };
36
- }
37
- }
38
-
39
16
  // GraphQL API, called from the client
40
17
  app.post('/api/graphql', async (c) => {
41
18
  const request = c.req.raw;
@@ -55,7 +32,10 @@ app.post('/api/graphql', async (c) => {
55
32
  app.get('*', async (c) => {
56
33
  const request = c.req.raw;
57
34
 
58
- const [{App}] = await Promise.all([import('./App.tsx')]);
35
+ const [{App}, {ServerAppContext}] = await Promise.all([
36
+ import('./App.tsx'),
37
+ import('./context/server.ts'),
38
+ ]);
59
39
 
60
40
  const context = new ServerAppContext(request);
61
41
 
@@ -9,7 +9,7 @@ import {Navigation, TestRouter} from '@quilted/quilt/navigation/testing';
9
9
  import {Localization} from '@quilted/quilt/localize';
10
10
  import {GraphQLCache} from '@quilted/quilt/graphql';
11
11
 
12
- import {AppContextPreact} from '~/shared/context.ts';
12
+ import {AppContextPreact} from '~/context/preact.ts';
13
13
 
14
14
  import {GraphQLTesting, GraphQLController} from '../graphql.ts';
15
15
 
@@ -32,18 +32,21 @@ export const renderApp = createRender<
32
32
  router = new TestRouter(),
33
33
  browser = new BrowserTestMock(),
34
34
  graphql = new GraphQLController(),
35
- graphQLCache = new GraphQLCache(),
35
+ graphQLCache = new GraphQLCache({fetch: graphql.fetch}),
36
36
  }) {
37
37
  return {
38
- router,
38
+ navigation: {router},
39
39
  browser,
40
- graphql: {fetch: graphql.fetch, cache: graphQLCache},
41
- graphQLController: graphql,
40
+ graphql: {fetch: graphql.fetch, cache: graphQLCache, controller: graphql},
42
41
  };
43
42
  },
44
43
  // Render all of our app-wide context providers around each component under test.
45
44
  render(element, context, {locale = 'en'}) {
46
- const {router, browser, graphql, graphQLController} = context;
45
+ const {
46
+ navigation: {router},
47
+ browser,
48
+ graphql,
49
+ } = context;
47
50
 
48
51
  return (
49
52
  <AppContextPreact.Provider value={context}>
@@ -51,7 +54,7 @@ export const renderApp = createRender<
51
54
  <Localization locale={locale}>
52
55
  <Navigation router={router}>
53
56
  <GraphQLTesting
54
- controller={graphQLController}
57
+ controller={graphql.controller}
55
58
  cache={graphql.cache}
56
59
  >
57
60
  <Suspense fallback={null}>{element}</Suspense>
@@ -69,7 +72,7 @@ export const renderApp = createRender<
69
72
  // once the data is ready.
70
73
 
71
74
  await wrapper.act(async () => {
72
- await wrapper.context.graphQLController.resolveAll();
75
+ await wrapper.context.graphql.controller.resolveAll();
73
76
  });
74
77
  },
75
78
  });
@@ -2,7 +2,7 @@ import type {TestRouter} from '@quilted/quilt/navigation/testing';
2
2
  import type {BrowserTestMock} from '@quilted/quilt/browser/testing';
3
3
  import type {GraphQLCache} from '@quilted/quilt/graphql';
4
4
 
5
- import type {AppContext} from '~/shared/context.ts';
5
+ import type {AppContext} from '~/context/types.ts';
6
6
 
7
7
  import type {GraphQLController} from '../graphql.ts';
8
8
 
@@ -58,7 +58,7 @@ export interface RenderContext extends AppContext {
58
58
  /**
59
59
  * The router used for this component test.
60
60
  */
61
- readonly router: TestRouter;
61
+ readonly navigation: {router: TestRouter};
62
62
 
63
63
  /**
64
64
  * The browser environment for this component test.
@@ -66,9 +66,14 @@ export interface RenderContext extends AppContext {
66
66
  readonly browser: BrowserTestMock;
67
67
 
68
68
  /**
69
- * The GraphQL controller used for this component test.
69
+ * The GraphQL context used for this component test.
70
70
  */
71
- readonly graphQLController: GraphQLController;
71
+ readonly graphql: AppContext['graphql'] & {
72
+ /**
73
+ * The GraphQL controller used for this component test.
74
+ */
75
+ readonly controller: GraphQLController;
76
+ };
72
77
  }
73
78
 
74
79
  export interface RenderActions extends Record<string, never> {}
@@ -3,7 +3,7 @@
3
3
  "compilerOptions": {
4
4
  "jsxImportSource": "preact",
5
5
  "paths": {
6
- "~/shared/*": ["./shared/*"],
6
+ "~/context/*": ["./context/*"],
7
7
  "~/tests/*": ["./tests/*"],
8
8
  "react": ["./node_modules/preact/compat"],
9
9
  "react-dom": ["./node_modules/preact/compat"]
@@ -9,12 +9,10 @@ import {Frame} from './foundation/frame.ts';
9
9
 
10
10
  import {Home} from './features/home.ts';
11
11
 
12
- import {trpc} from './shared/trpc.ts';
13
- import {
14
- AppContextPreact,
15
- type AppContext as AppContextType,
16
- } from './shared/context.ts';
17
- import {routeWithAppContext} from './shared/navigation.ts';
12
+ import {trpc} from './context/trpc.ts';
13
+ import type {AppContext as AppContextType} from './context/types.ts';
14
+ import {AppContextPreact} from './context/preact.ts';
15
+ import {routeWithAppContext} from './context/navigation.ts';
18
16
 
19
17
  export interface AppProps {
20
18
  context: AppContextType;
@@ -47,7 +45,7 @@ export function App({context}: AppProps) {
47
45
  <Localization>
48
46
  <Head />
49
47
  <Navigation
50
- router={context.router}
48
+ router={context.navigation.router}
51
49
  routes={routes}
52
50
  context={context}
53
51
  />
@@ -0,0 +1,10 @@
1
+ *,
2
+ *::before,
3
+ *::after {
4
+ box-sizing: border-box;
5
+ }
6
+
7
+ html,
8
+ body {
9
+ margin: 0;
10
+ }
@@ -1,29 +1,12 @@
1
+ import './browser.css';
2
+
1
3
  import type {ComponentChild} from 'preact';
2
4
  import {hydrate} from '@quilted/quilt/browser';
3
- import {Router} from '@quilted/quilt/navigation';
4
-
5
- import {httpBatchLink} from '@trpc/client';
6
- import {QueryClient} from '@tanstack/react-query';
7
5
 
8
- import type {AppContext} from '~/shared/context.ts';
9
- import {trpc} from '~/shared/trpc.ts';
6
+ import {BrowserAppContext} from '~/context/browser.ts';
10
7
 
11
8
  import {App} from './App.tsx';
12
9
 
13
- class BrowserAppContext implements AppContext {
14
- readonly router: Router;
15
- readonly trpc: AppContext['trpc'];
16
- readonly queryClient: QueryClient;
17
-
18
- constructor() {
19
- this.router = new Router();
20
- this.queryClient = new QueryClient();
21
- this.trpc = trpc.createClient({
22
- links: [httpBatchLink({url: new URL('/api', window.location.href).href})],
23
- });
24
- }
25
- }
26
-
27
10
  class BrowserApp {
28
11
  /**
29
12
  * The app's globally-available context.
@@ -44,7 +27,7 @@ class BrowserApp {
44
27
  // @example
45
28
  // ```js
46
29
  // // Log the current URL
47
- // console.log(globalThis.app.context.router.currentRequest.url);
30
+ // console.log(globalThis.app.context.navigation.router.currentRequest.url);
48
31
  // ```
49
32
  Object.defineProperty(globalThis, 'app', {
50
33
  value: this,
@@ -53,8 +36,11 @@ class BrowserApp {
53
36
  writable: true,
54
37
  });
55
38
  }
39
+
40
+ hydrate() {
41
+ hydrate(this.rendered);
42
+ }
56
43
  }
57
44
 
58
45
  const app = new BrowserApp();
59
-
60
- hydrate(app.rendered);
46
+ app.hydrate();
@@ -0,0 +1,20 @@
1
+ import {httpBatchLink} from '@trpc/client';
2
+ import {QueryClient} from '@tanstack/react-query';
3
+
4
+ import type {AppContext} from './types.ts';
5
+ import {NavigationForApp} from './navigation.ts';
6
+ import {trpc} from './trpc.ts';
7
+
8
+ export class BrowserAppContext implements AppContext {
9
+ readonly navigation: NavigationForApp;
10
+ readonly trpc: AppContext['trpc'];
11
+ readonly queryClient: QueryClient;
12
+
13
+ constructor() {
14
+ this.navigation = new NavigationForApp();
15
+ this.queryClient = new QueryClient();
16
+ this.trpc = trpc.createClient({
17
+ links: [httpBatchLink({url: new URL('/api', window.location.href).href})],
18
+ });
19
+ }
20
+ }
@@ -0,0 +1,17 @@
1
+ import {createContextRouteFunction, Router} from '@quilted/quilt/navigation';
2
+
3
+ import type {AppContext} from './types.ts';
4
+
5
+ export interface Navigation {
6
+ readonly router: Router;
7
+ }
8
+
9
+ export class NavigationForApp implements Navigation {
10
+ readonly router: Router;
11
+
12
+ constructor(url?: string | URL) {
13
+ this.router = new Router(url);
14
+ }
15
+ }
16
+
17
+ export const routeWithAppContext = createContextRouteFunction<AppContext>();
@@ -1,6 +1,6 @@
1
1
  import {createOptionalContext} from '@quilted/quilt/context';
2
2
 
3
- export interface AppContext {}
3
+ import type {AppContext} from './types.ts';
4
4
 
5
5
  export const AppContextPreact = createOptionalContext<AppContext>();
6
6
  export const useAppContext = AppContextPreact.use;
@@ -0,0 +1,18 @@
1
+ import {createDirectClient} from '@quilted/trpc/server';
2
+ import {QueryClient} from '@tanstack/react-query';
3
+
4
+ import type {AppContext} from './types.ts';
5
+ import {NavigationForApp} from './navigation.ts';
6
+ import {appRouter} from '../trpc.ts';
7
+
8
+ export class ServerAppContext implements AppContext {
9
+ readonly navigation: NavigationForApp;
10
+ readonly trpc: AppContext['trpc'];
11
+ readonly queryClient: QueryClient;
12
+
13
+ constructor(request: Request) {
14
+ this.navigation = new NavigationForApp(request.url);
15
+ this.trpc = createDirectClient(appRouter);
16
+ this.queryClient = new QueryClient();
17
+ }
18
+ }
@@ -0,0 +1,6 @@
1
+ import {createTRPCReact, type CreateTRPCReact} from '@trpc/react-query';
2
+
3
+ import type {AppRouter} from '../trpc.ts';
4
+
5
+ export const trpc: CreateTRPCReact<AppRouter, {}> =
6
+ createTRPCReact<AppRouter>();
@@ -0,0 +1,11 @@
1
+ import type {Navigation} from './navigation.ts';
2
+ import type {TRPCUntypedClient} from '@trpc/client';
3
+ import type {QueryClient} from '@tanstack/react-query';
4
+
5
+ import type {AppRouter} from '../trpc.ts';
6
+
7
+ export interface AppContext {
8
+ readonly navigation: Navigation;
9
+ readonly trpc: TRPCUntypedClient<AppRouter>;
10
+ readonly queryClient: QueryClient;
11
+ }
@@ -1,4 +1,4 @@
1
- import {trpc} from '~/shared/trpc.ts';
1
+ import {trpc} from '~/context/trpc.ts';
2
2
 
3
3
  import styles from './Home.module.css';
4
4
 
@@ -6,34 +6,16 @@ import {
6
6
  PermissionsPolicyHeader,
7
7
  StrictTransportSecurityHeader,
8
8
  } from '@quilted/quilt/server';
9
- import {Router} from '@quilted/quilt/navigation';
10
-
11
9
  import Env from 'quilt:module/env';
12
10
  import {BrowserAssets} from 'quilt:module/assets';
13
11
 
14
- import {createDirectClient} from '@quilted/trpc/server';
15
12
  import {fetchRequestHandler} from '@trpc/server/adapters/fetch';
16
- import {QueryClient} from '@tanstack/react-query';
17
-
18
- import type {AppContext} from '~/shared/context.ts';
19
13
 
20
14
  import {appRouter} from './trpc.ts';
21
15
 
22
16
  const app = new Hono();
23
17
  const assets = new BrowserAssets();
24
18
 
25
- class ServerAppContext implements AppContext {
26
- readonly router: Router;
27
- readonly trpc: AppContext['trpc'];
28
- readonly queryClient: QueryClient;
29
-
30
- constructor(request: Request) {
31
- this.router = new Router(request.url);
32
- this.trpc = createDirectClient(appRouter);
33
- this.queryClient = new QueryClient();
34
- }
35
- }
36
-
37
19
  // TRPC API
38
20
  app.all('/api/*', async (c) => {
39
21
  const request = c.req.raw;
@@ -49,7 +31,10 @@ app.all('/api/*', async (c) => {
49
31
  app.get('*', async (c) => {
50
32
  const request = c.req.raw;
51
33
 
52
- const [{App}] = await Promise.all([import('./App.tsx')]);
34
+ const [{App}, {ServerAppContext}] = await Promise.all([
35
+ import('./App.tsx'),
36
+ import('./context/server.ts'),
37
+ ]);
53
38
 
54
39
  const context = new ServerAppContext(request);
55
40
 
@@ -8,8 +8,8 @@ import {Localization} from '@quilted/quilt/localize';
8
8
 
9
9
  import {QueryClient, QueryClientProvider} from '@tanstack/react-query';
10
10
 
11
- import {trpc} from '~/shared/trpc.ts';
12
- import {AppContextPreact} from '~/shared/context.ts';
11
+ import {trpc} from '~/context/trpc.ts';
12
+ import {AppContextPreact} from '~/context/preact.ts';
13
13
 
14
14
  import {RenderOptions, RenderContext, RenderActions} from './types.ts';
15
15
 
@@ -28,7 +28,7 @@ export const renderApp = createRender<
28
28
  // React tree and your test code, and is ideal for mocking out global context providers.
29
29
  context({router = new TestRouter(), browser = new BrowserTestMock()}) {
30
30
  return {
31
- router,
31
+ navigation: {router},
32
32
  browser,
33
33
  trpc: trpc.createClient(),
34
34
  queryClient: new QueryClient(),
@@ -36,7 +36,12 @@ export const renderApp = createRender<
36
36
  },
37
37
  // Render all of our app-wide context providers around each component under test.
38
38
  render(element, context, {locale = 'en'}) {
39
- const {router, browser, trpc: trpcClient, queryClient} = context;
39
+ const {
40
+ navigation: {router},
41
+ browser,
42
+ trpc: trpcClient,
43
+ queryClient,
44
+ } = context;
40
45
 
41
46
  return (
42
47
  <AppContextPreact.Provider value={context}>
@@ -2,7 +2,7 @@ import type {TestRouter} from '@quilted/quilt/navigation/testing';
2
2
  import type {BrowserTestMock} from '@quilted/quilt/browser/testing';
3
3
  import type {QueryClient} from '@tanstack/react-query';
4
4
 
5
- import type {AppContext} from '~/shared/context.ts';
5
+ import type {AppContext} from '~/context/types.ts';
6
6
 
7
7
  export interface RenderOptions {
8
8
  /**
@@ -28,7 +28,7 @@ export interface RenderContext extends AppContext {
28
28
  /**
29
29
  * The router used for this component test.
30
30
  */
31
- readonly router: TestRouter;
31
+ readonly navigation: {router: TestRouter};
32
32
 
33
33
  /**
34
34
  * The browser environment for this component test.
@@ -3,7 +3,7 @@
3
3
  "compilerOptions": {
4
4
  "jsxImportSource": "preact",
5
5
  "paths": {
6
- "~/shared/*": ["./shared/*"],
6
+ "~/context/*": ["./context/*"],
7
7
  "~/tests/*": ["./tests/*"],
8
8
  "react": ["./node_modules/preact/compat"],
9
9
  "react-dom": ["./node_modules/preact/compat"]
@@ -1,15 +0,0 @@
1
- import type {Router} from '@quilted/quilt/navigation';
2
- import {createContextRouteFunction} from '@quilted/quilt/navigation';
3
-
4
- import type {AppContext} from '~/shared/context.ts';
5
-
6
- declare module '~/shared/context.ts' {
7
- interface AppContext {
8
- /**
9
- * The router used to control navigation throughout the application.
10
- */
11
- readonly router: Router;
12
- }
13
- }
14
-
15
- export const routeWithAppContext = createContextRouteFunction<AppContext>();
@@ -1,22 +0,0 @@
1
- import type {GraphQLFetch, GraphQLCache} from '@quilted/quilt/graphql';
2
-
3
- declare module '~/shared/context.ts' {
4
- interface AppContext {
5
- /**
6
- * The app’s GraphQL client.
7
- */
8
- readonly graphql: {
9
- /**
10
- * A function to perform GraphQL operations.
11
- */
12
- readonly fetch: GraphQLFetch;
13
-
14
- /**
15
- * The app’s GraphQL cache.
16
- */
17
- readonly cache: GraphQLCache;
18
- };
19
- }
20
- }
21
-
22
- export {};
@@ -1,15 +0,0 @@
1
- import type {Router} from '@quilted/quilt/navigation';
2
- import {createContextRouteFunction} from '@quilted/quilt/navigation';
3
-
4
- import type {AppContext} from '~/shared/context.ts';
5
-
6
- declare module '~/shared/context.ts' {
7
- interface AppContext {
8
- /**
9
- * The router used to control navigation throughout the application.
10
- */
11
- readonly router: Router;
12
- }
13
- }
14
-
15
- export const routeWithAppContext = createContextRouteFunction<AppContext>();
@@ -1,15 +0,0 @@
1
- import type {Router} from '@quilted/quilt/navigation';
2
- import {createContextRouteFunction} from '@quilted/quilt/navigation';
3
-
4
- import type {AppContext} from '~/shared/context.ts';
5
-
6
- declare module '~/shared/context.ts' {
7
- interface AppContext {
8
- /**
9
- * The router used to control navigation throughout the application.
10
- */
11
- readonly router: Router;
12
- }
13
- }
14
-
15
- export const routeWithAppContext = createContextRouteFunction<AppContext>();
@@ -1,18 +0,0 @@
1
- import type {TRPCUntypedClient} from '@trpc/client';
2
- import {createTRPCReact, type CreateTRPCReact} from '@trpc/react-query';
3
- import type {QueryClient} from '@tanstack/react-query';
4
-
5
- // Get access to our app’s router type signature, which will
6
- // provide strong typing on the queries and mutations we can
7
- // perform.
8
- import type {AppRouter} from '../trpc.ts';
9
-
10
- export const trpc: CreateTRPCReact<AppRouter, {}> =
11
- createTRPCReact<AppRouter>();
12
-
13
- declare module '~/shared/context.ts' {
14
- interface AppContext {
15
- trpc: TRPCUntypedClient<AppRouter>;
16
- queryClient: QueryClient;
17
- }
18
- }