Skip to content

Commit cfcad09

Browse files
committed
Update docs
1 parent b13fdd9 commit cfcad09

7 files changed

Lines changed: 89 additions & 85 deletions

File tree

docs/configuration.md

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,37 @@ You've installed Superglue and now you're ready to configure your app.
22

33
## `application.js`
44

5-
This is the entry point of your application and uses Superglue's `createApp`
6-
function. You can add a custom layout here.
5+
This is the entry point of your application. You can add a custom layout here.
76

87
```tsx
9-
<Provider>
10-
<MyLayout>
11-
<Outlet />
12-
</MyLayout>
13-
</Provider>
8+
import { createApp } from "@thoughtbot/superglue";
9+
10+
...
11+
12+
const { Provider, Outlet, ujs } = createApp({
13+
// The base url prefixed to all calls made by `visit` and `remote`.
14+
baseUrl: location.origin,
15+
// The global var SUPERGLUE_INITIAL_PAGE_STATE is set by your erb
16+
// template, e.g., index.html.erb
17+
initialPage: window.SUPERGLUE_INITIAL_PAGE_STATE,
18+
// The initial path of the page, e.g., /foobar
19+
path: location.pathname + location.search + location.hash,
20+
// Callback used to setup visit and remote
21+
buildVisitAndRemote,
22+
// Mapping between the page identifier to page component
23+
mapping: pageIdentifierToPageComponent,
24+
});
25+
26+
const root = createRoot(appEl);
27+
root.render(
28+
<div onClick={ujs.onClick} onSubmit={ujs.onSubmit}>
29+
<Provider>
30+
<MyLayout>
31+
<Outlet />
32+
</MyLayout>
33+
</Provider>
34+
</div>,
35+
);
1436
```
1537

1638
## `page_to_page_mapping.js`
@@ -61,7 +83,7 @@ submission to replace history instead of the usual push.
6183
```js
6284
const navigationAction = !!dataset?.sgReplace
6385
? "replace"
64-
: meta.navigationAction
86+
: result.navigationAction
6587
```
6688
6789
This is where you'll add [progress bars], error handling, custom UJS attributes,

docs/page-response.md

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -59,19 +59,8 @@ The parts of your page that have been marked for [deferment](./deferments.md).
5959

6060
### `assets`
6161
An `array` of asset fingerprint `string`s. Used by Superglue to detect the need to
62-
refresh the browser due to new assets. You can control the refresh behavior in
63-
`application_visit.js`:
64-
65-
```js
66-
/**
67-
* The assets fingerprints changed, instead of transitioning
68-
* just go to the URL directly to retrieve new assets
69-
*/
70-
if (meta.needsRefresh) {
71-
window.location.href = meta.pageKey
72-
return meta
73-
}
74-
```
62+
refresh the browser due to new assets. When Superglue detects that the assets have
63+
changed, it automatically performs a full page reload to retrieve the new assets.
7564

7665
### `csrfToken`
7766
The authenticity token that Superglue will use for non-GET request made by using

docs/recipes/progress-bar.md

Lines changed: 10 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@ And make the following edits to `application_visit.js`
1414
````diff
1515
+ import { requestStripe } from 'request-stripe';
1616

17-
export function buildVisitAndRemote({navigateTo, visit, remote}) {
18-
const appRemote = (path, {dataset, options} = {}) => {
17+
export const buildVisitAndRemote = ({navigateTo, visit, remote}) => {
18+
const appRemote = (path, {dataset, ...options} = {}) => {
1919
/**
2020
* You can make use of `dataset` to add custom UJS options.
2121
* If you are implementing a progress bar, you can selectively
@@ -31,49 +31,25 @@ export function buildVisitAndRemote({navigateTo, visit, remote}) {
3131
*/
3232
+ const done = requestStripe()
3333
return remote(path, options)
34-
+ .finally(() => done())
34+
+ .finally(() => done())
3535
}
3636

3737
const appVisit = (path, {dataset, ...options} = {}) => {
3838
+ const done = requestStripe()
3939
return visit(path, options)
40-
.then((meta) => {
41-
if (meta.needsRefresh) {
42-
window.location = meta.url
43-
return
44-
}
45-
46-
navigateTo(meta.pageKey, {
47-
action: meta.navigationAction,
40+
.then(result => {
41+
const navigationAction = !!dataset?.sgReplace
42+
? "replace"
43+
: result.navigationAction
44+
navigateTo(result.pageKey, {
45+
action: navigationAction,
4846
})
4947

50-
return meta
48+
return result
5149
})
5250
.finally(() => {
5351
+ done()
5452
})
55-
.catch((err) => {
56-
const response = err.response
57-
58-
if (!response) {
59-
console.error(err)
60-
return
61-
}
62-
63-
if (response.ok) {
64-
window.location = response.url
65-
} else {
66-
if (response.status >= 400 && response.status < 500) {
67-
window.location = '/400.html'
68-
return
69-
}
70-
71-
if (response.status >= 500) {
72-
window.location = '/500.html'
73-
return
74-
}
75-
}
76-
})
7753
}
7854

7955
return { visit: appVisit, remote: appRemote }

docs/recipes/ssr.md

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -139,12 +139,13 @@ Change your `application.js` to use `hydrateRoot`:
139139

140140
and change the rest of `application.js` accordingly. For example:
141141

142-
```js
142+
```jsx
143143
import React from 'react';
144144
import { createApp } from '@thoughtbot/superglue';
145145
import { hydrateRoot } from 'react-dom/client';
146146
import { buildVisitAndRemote } from './application_visit';
147147
import { pageIdentifierToPageComponent } from './page_to_page_mapping';
148+
import { Layout } from './components';
148149

149150
if (typeof window !== "undefined") {
150151
document.addEventListener("DOMContentLoaded", function () {
@@ -161,7 +162,13 @@ if (typeof window !== "undefined") {
161162
})
162163

163164
hydrateRoot(appEl,
164-
<Provider><Outlet /></Provider>
165+
<div onClick={ujs.onClick} onSubmit={ujs.onSubmit}>
166+
<Provider>
167+
<Layout>
168+
<Outlet />
169+
</Layout>
170+
</Provider>
171+
</div>
165172
);
166173
}
167174
});

docs/recipes/turbo.md

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,13 @@ In your `application_visit.js` file:
1010

1111
+ import { urlToPageKey } from '@thoughtbot/superglue'
1212

13-
const appVisit = (...args) => {
13+
const appVisit = (path, {dataset, ...options} = {}) => {
14+
+ const pageKey = urlToPageKey(path)
15+
+ // attempt to navigate first
16+
+ navigateTo(pageKey)
1417

15-
const pageKey = urlToPageKey(args[0])
16-
+ // attempt to navigate first
17-
+ navigateTo(pageKey)
18-
19-
return visit(...args)
20-
....
18+
return visit(path, options)
19+
....
2120
```
2221

2322
This is different from [restore strategy] which controls what happens

docs/runtime-types.md

Lines changed: 32 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,7 @@
33
End-to-end typing is a common way to ensure correctness across the frontend
44
and backend, but it's not the only way. Tools like Typelizer annotate types in
55
Ruby and regenerate them in TypeScript, but now you're learning two different
6-
type languages and wondering how one maps to the other. TypeScript is just so
7-
much more expressive. It has union types, mapped types, conditional types, and
8-
generics that Ruby's type systems can't match.
6+
type languages and wondering how one maps to the other.
97

108
Superglue takes a different approach, a typescript first approach. Instead of
119
end-to-end typing, we use
@@ -15,10 +13,9 @@ what the component needs (a header, a list of posts, each with a title and
1513
body) via `useContent<T>()`. Then you build the props template to fulfill it.
1614
The UI shape comes first, the business logic follows.
1715

18-
You can use any runtime type validation library you like. Superglue includes
19-
experimental support for [Deepkit](https://deepkit.io/), which validates your
20-
server responses against your TypeScript types during development. Write the
21-
type, load the page, and the errors will guide you.
16+
Superglue ships an experimental [Deepkit](https://deepkit.io/) plugin that
17+
validates your server responses against your TypeScript types during
18+
development. Write the type, load the page, and the errors will guide you.
2219

2320
## Getting started with Deepkit
2421

@@ -28,27 +25,42 @@ To get started, run the installation generator with the typescript flag.
2825
rails g superglue:install --typescript
2926
```
3027

31-
The installation generator will add
28+
The installation generator will ask if you'd like to enable Deepkit and set up
29+
the build plugin for your bundler. If you prefer to set it up manually, add the
30+
plugin to your build config:
3231

33-
1. a [esbuild plugin](https://github.com/thoughtbot/superglue_rails/blob/af7edd35d3ed211822663ac21a5c9910abcc6d88/lib/generators/superglue/install/templates/esbuild/plugin.js) that enables deepkit to work with Superglue
34-
2. a [build.mjs](https://github.com/thoughtbot/superglue_rails/blob/af7edd35d3ed211822663ac21a5c9910abcc6d88/lib/generators/superglue/install/templates/ts/build.mjs), a esbuild node script that builds your application.
35-
3. And setup deepkit to work with esbuild. If you are using [vite](./recipes/vite.md) or bun with superglue, please use [deepkit/vite](https://deepkit.io/en/documentation/package/vite) or [deepkit/bun](https://deepkit.io/en/documentation/package/bun) plugins.
32+
```javascript
33+
// esbuild
34+
import { esbuild as deepkitPlugin } from '@thoughtbot/superglue/deepkit'
3635

37-
## How It Works
36+
// vite
37+
import { vite as deepkitPlugin } from '@thoughtbot/superglue/deepkit'
3838

39-
Deepkit provides runtime type validation during development:
39+
// webpack
40+
const { webpack: deepkitPlugin } = require('@thoughtbot/superglue/deepkit')
41+
```
4042

41-
1. **Build Time**: Deepkit's compiler transforms TypeScript types into runtime validation code
42-
2. **Development Mode**: `useContent()` validates server responses against your types
43-
3. **Production Mode**: Validation code is stripped entirely
43+
Then include it conditionally in your plugins array:
44+
45+
```javascript
46+
plugins: isDev ? [deepkitPlugin()] : []
47+
```
48+
49+
## How It Works
50+
51+
The Superglue Deepkit plugin transforms `useContent<T>()` and
52+
`useFragment<T>()` calls to inject a `validate` callback via AST
53+
transformation. Deepkit's compiler generates the runtime type metadata.
54+
When the page loads, the hooks validate server responses against your
55+
types and log errors to the console.
4456

4557
## Writing your types
4658

4759
`useContent` is the generic hook used to access the props [you
4860
build](shaping.md). To make use of runtime types, simply pass a type
49-
describing your page's props as you normally would:
61+
describing your page's props as you normally would:
5062

51-
For example:
63+
For example:
5264

5365
```tsx
5466
import React from 'react'
@@ -71,7 +83,7 @@ For example:
7183
return (
7284
<div>
7385
<h1>{header}</h1>
74-
86+
7587
<ul>
7688
<li>{post.id}</li>
7789
<li>{post.title}</li>
@@ -96,4 +108,4 @@ json.post do
96108
json.title "This is a title"
97109
json.content "This is a body"
98110
end
99-
```
111+
```

mkdocs.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,6 @@ nav:
114114
- Client-Side updates: client-updates.md
115115
- Digging: digging.md
116116
- Deferments: deferments.md
117-
- Redux: redux.md
118117

119118
- Navigating:
120119
- The return of Rails UJS: ujs.md

0 commit comments

Comments
 (0)