superglue 2.0.0.alpha.10 → 2.0.0.beta.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.
- checksums.yaml +4 -4
- data/app/channels/superglue/streams/broadcasts.rb +4 -34
- data/app/helpers/superglue/streams_helper.rb +2 -2
- data/app/models/concerns/superglue/broadcastable.rb +10 -36
- data/lib/generators/superglue/install/install_generator.rb +193 -25
- data/lib/generators/superglue/install/templates/application.json.props +1 -3
- data/lib/generators/superglue/install/templates/bun/bun.config.deepkit.js +38 -0
- data/lib/generators/superglue/install/templates/bun/bun.config.js +34 -0
- data/lib/generators/superglue/install/templates/bun/bun.config.ts.js +34 -0
- data/lib/generators/superglue/install/templates/bun/page_to_page_mapping.js +10 -0
- data/lib/generators/superglue/install/templates/bun/page_to_page_mapping.ts +10 -0
- data/lib/generators/superglue/install/templates/js/application.jsx +24 -18
- data/lib/generators/superglue/install/templates/js/application_visit.js +31 -61
- data/lib/generators/superglue/install/templates/js/build.mjs +26 -0
- data/lib/generators/superglue/install/templates/js/flash.js +6 -47
- data/lib/generators/superglue/install/templates/js/layout.jsx +2 -2
- data/lib/generators/superglue/install/templates/rollup/page_to_page_mapping.js +9 -0
- data/lib/generators/superglue/install/templates/rollup/page_to_page_mapping.ts +9 -0
- data/lib/generators/superglue/install/templates/rollup/rollup.config.deepkit.js +37 -0
- data/lib/generators/superglue/install/templates/rollup/rollup.config.js +32 -0
- data/lib/generators/superglue/install/templates/rollup/rollup.config.ts.js +35 -0
- data/lib/generators/superglue/install/templates/stream.json.props +1 -3
- data/lib/generators/superglue/install/templates/ts/application.tsx +24 -18
- data/lib/generators/superglue/install/templates/ts/application_visit.ts +35 -64
- data/lib/generators/superglue/install/templates/ts/build.deepkit.mjs +27 -0
- data/lib/generators/superglue/install/templates/ts/build.mjs +26 -0
- data/lib/generators/superglue/install/templates/ts/flash.ts +16 -48
- data/lib/generators/superglue/install/templates/ts/layout.tsx +2 -2
- data/lib/generators/superglue/install/templates/ts/page_to_page_mapping.ts +3 -1
- data/lib/generators/superglue/install/templates/ts/tsconfig.json +2 -2
- data/lib/generators/superglue/install/templates/webpack/page_to_page_mapping.js +9 -0
- data/lib/generators/superglue/install/templates/webpack/page_to_page_mapping.ts +9 -0
- data/lib/generators/superglue/install/templates/webpack/webpack.config.deepkit.js +42 -0
- data/lib/generators/superglue/install/templates/webpack/webpack.config.js +40 -0
- data/lib/generators/superglue/install/templates/webpack/webpack.config.ts.js +40 -0
- data/lib/generators/superglue/view_collection/templates/js/edit.jsx +7 -6
- data/lib/generators/superglue/view_collection/templates/js/new.jsx +9 -8
- data/lib/generators/superglue/view_collection/templates/ts/edit.tsx +9 -8
- data/lib/generators/superglue/view_collection/templates/ts/new.tsx +10 -9
- data/lib/superglue/engine.rb +0 -1
- data/lib/superglue/rendering.rb +18 -4
- data/lib/superglue.rb +0 -10
- metadata +21 -8
- data/app/controllers/concerns/superglue/request_id_tracking.rb +0 -16
- data/app/models/superglue/debouncer.rb +0 -28
- data/app/models/superglue/thread_debouncer.rb +0 -30
- data/lib/generators/superglue/install/templates/js/store.js +0 -31
- data/lib/generators/superglue/install/templates/ts/store.ts +0 -35
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import { visit, remote } from "@thoughtbot/superglue/action_creators"
|
|
2
|
-
|
|
3
1
|
/**
|
|
4
2
|
* This function returns a wrapped visit and remote that will be used by UJS,
|
|
5
3
|
* the Navigation component, and passed to your page components through the
|
|
@@ -8,7 +6,7 @@ import { visit, remote } from "@thoughtbot/superglue/action_creators"
|
|
|
8
6
|
* You can customize both functions to your liking. For example, for a progress
|
|
9
7
|
* bar. This file also adds support for data-sg-remote.
|
|
10
8
|
*/
|
|
11
|
-
export const buildVisitAndRemote = (
|
|
9
|
+
export const buildVisitAndRemote = ({ navigateTo, visit, remote }) => {
|
|
12
10
|
const appRemote = (path, { dataset, ...options } = {}) => {
|
|
13
11
|
/**
|
|
14
12
|
* You can make use of `dataset` to add custom UJS options.
|
|
@@ -23,27 +21,38 @@ export const buildVisitAndRemote = (ref, store) => {
|
|
|
23
21
|
*
|
|
24
22
|
* This would be available as `sgHideProgress` on the dataset
|
|
25
23
|
*/
|
|
26
|
-
return
|
|
24
|
+
return remote(path, options).then(result => {
|
|
25
|
+
if (result.hasError) {
|
|
26
|
+
const { response } = result
|
|
27
|
+
|
|
28
|
+
if (response.status >= 400 && response.status < 500) {
|
|
29
|
+
window.location.href = "/400.html"
|
|
30
|
+
} else if (response.status >= 500) {
|
|
31
|
+
window.location.href = "/500.html"
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return result
|
|
36
|
+
})
|
|
27
37
|
}
|
|
28
38
|
|
|
29
39
|
const appVisit = (path, { dataset, ...options } = {}) => {
|
|
30
40
|
/**
|
|
31
41
|
* Do something before we make a request.
|
|
32
42
|
* e.g, show a [progress bar](https://thoughtbot.github.io/superglue/recipes/progress-bar/).
|
|
33
|
-
*
|
|
34
|
-
* Hint: you can access the current pageKey
|
|
35
|
-
* via `store.getState().superglue.currentPageKey`
|
|
36
43
|
*/
|
|
37
|
-
return
|
|
38
|
-
.
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
44
|
+
return visit(path, options)
|
|
45
|
+
.then(result => {
|
|
46
|
+
if (result.hasError) {
|
|
47
|
+
const { response } = result
|
|
48
|
+
|
|
49
|
+
if (response.status >= 400 && response.status < 500) {
|
|
50
|
+
window.location.href = "/400.html"
|
|
51
|
+
} else if (response.status >= 500) {
|
|
52
|
+
window.location.href = "/500.html"
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return result
|
|
47
56
|
}
|
|
48
57
|
|
|
49
58
|
/**
|
|
@@ -52,19 +61,14 @@ export const buildVisitAndRemote = (ref, store) => {
|
|
|
52
61
|
* This option overrides the `navigationAction` to allow a link click or
|
|
53
62
|
* a form submission to replace history instead of the usual push.
|
|
54
63
|
*/
|
|
55
|
-
const
|
|
64
|
+
const navigationAction = !!dataset?.sgReplace
|
|
56
65
|
? "replace"
|
|
57
|
-
:
|
|
58
|
-
|
|
59
|
-
action:
|
|
66
|
+
: result.navigationAction
|
|
67
|
+
navigateTo(result.pageKey, {
|
|
68
|
+
action: navigationAction
|
|
60
69
|
})
|
|
61
70
|
|
|
62
|
-
|
|
63
|
-
* Return the meta object, it's used for scroll restoration when
|
|
64
|
-
* handling the back button. You can skip returning, but Superglue
|
|
65
|
-
* will warn you about scroll restoration.
|
|
66
|
-
*/
|
|
67
|
-
return meta
|
|
71
|
+
return result
|
|
68
72
|
})
|
|
69
73
|
.finally(() => {
|
|
70
74
|
/**
|
|
@@ -73,40 +77,6 @@ export const buildVisitAndRemote = (ref, store) => {
|
|
|
73
77
|
* This is where you hide a progress bar.
|
|
74
78
|
*/
|
|
75
79
|
})
|
|
76
|
-
.catch(err => {
|
|
77
|
-
const response = err.response
|
|
78
|
-
|
|
79
|
-
if (!response) {
|
|
80
|
-
/**
|
|
81
|
-
* This is for errors that are NOT from a HTTP request.
|
|
82
|
-
*
|
|
83
|
-
* Tooling like Sentry can capture console errors. If not, feel
|
|
84
|
-
* free to customize to send the error to your telemetry tool of choice.
|
|
85
|
-
*/
|
|
86
|
-
console.error(err)
|
|
87
|
-
return
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
if (response.ok) {
|
|
91
|
-
/**
|
|
92
|
-
* This is for errors that are from a HTTP request.
|
|
93
|
-
*
|
|
94
|
-
* If the response is OK, it must be an HTML body, we'll
|
|
95
|
-
* go to that locaton directly.
|
|
96
|
-
*/
|
|
97
|
-
window.location = response.url
|
|
98
|
-
} else {
|
|
99
|
-
if (response.status >= 400 && response.status < 500) {
|
|
100
|
-
window.location.href = "/400.html"
|
|
101
|
-
return
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
if (response.status >= 500) {
|
|
105
|
-
window.location.href = "/500.html"
|
|
106
|
-
return
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
})
|
|
110
80
|
}
|
|
111
81
|
|
|
112
82
|
return { visit: appVisit, remote: appRemote }
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import * as esbuild from 'esbuild'
|
|
2
|
+
|
|
3
|
+
const isWatch = process.argv.includes('--watch')
|
|
4
|
+
|
|
5
|
+
const buildOptions = {
|
|
6
|
+
entryPoints: [
|
|
7
|
+
'app/javascript/application.jsx',
|
|
8
|
+
],
|
|
9
|
+
bundle: true,
|
|
10
|
+
sourcemap: true,
|
|
11
|
+
format: 'esm',
|
|
12
|
+
outdir: 'app/assets/builds',
|
|
13
|
+
publicPath: '/assets',
|
|
14
|
+
plugins: process.env.NODE_ENV === 'production' ? [] : [] ,
|
|
15
|
+
metafile: true,
|
|
16
|
+
conditions: process.env.NODE_ENV === 'production' ? ['production'] : [],
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
if (isWatch) {
|
|
20
|
+
const ctx = await esbuild.context(buildOptions)
|
|
21
|
+
await ctx.watch()
|
|
22
|
+
console.log('Watching for changes...')
|
|
23
|
+
} else {
|
|
24
|
+
const result = await esbuild.build(buildOptions)
|
|
25
|
+
console.log(await esbuild.analyzeMetafile(result.metafile))
|
|
26
|
+
}
|
|
@@ -1,48 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { receiveResponse , beforeVisit } from "@thoughtbot/superglue"
|
|
1
|
+
import { useFlash } from "@thoughtbot/superglue"
|
|
3
2
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
reducers: {
|
|
10
|
-
clearFlash(state, { payload }) {
|
|
11
|
-
const key = payload
|
|
12
|
-
if (!key) {
|
|
13
|
-
return {}
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
delete state[key]
|
|
17
|
-
|
|
18
|
-
return {
|
|
19
|
-
...state
|
|
20
|
-
}
|
|
21
|
-
},
|
|
22
|
-
flash(state, { payload }) {
|
|
23
|
-
return {
|
|
24
|
-
...state,
|
|
25
|
-
...payload
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
},
|
|
29
|
-
extraReducers: builder => {
|
|
30
|
-
builder.addCase(beforeVisit, (_state, _action) => {
|
|
31
|
-
return {}
|
|
32
|
-
})
|
|
33
|
-
builder.addCase(receiveResponse , (state, action) => {
|
|
34
|
-
const { response } = action.payload
|
|
35
|
-
|
|
36
|
-
if(response.slices) {
|
|
37
|
-
return {
|
|
38
|
-
...state,
|
|
39
|
-
...response.slices.flash
|
|
40
|
-
}
|
|
41
|
-
} else {
|
|
42
|
-
return state
|
|
43
|
-
}
|
|
44
|
-
})
|
|
45
|
-
}
|
|
46
|
-
})
|
|
47
|
-
|
|
48
|
-
export const { clearFlash, flash } = flashSlice.actions
|
|
3
|
+
/**
|
|
4
|
+
* A typed wrapper around useFlash. Customize the return shape
|
|
5
|
+
* to match the flash keys your application uses.
|
|
6
|
+
*/
|
|
7
|
+
export const useAppFlash = () => useFlash()
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import React from 'react'
|
|
2
|
-
import {
|
|
2
|
+
import { useAppFlash } from '@javascript/flash'
|
|
3
3
|
|
|
4
4
|
export const Layout = ({children}) => {
|
|
5
|
-
const flash =
|
|
5
|
+
const flash = useAppFlash()
|
|
6
6
|
|
|
7
7
|
return (
|
|
8
8
|
<div>
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
const pageIdentifierToPageComponent = {}
|
|
2
|
+
const pages = import.meta.glob('../views/**/*.jsx', { eager: true })
|
|
3
|
+
|
|
4
|
+
for (const key in pages) {
|
|
5
|
+
const identifier = key.replace('../views/', '').split('.')[0]
|
|
6
|
+
pageIdentifierToPageComponent[identifier] = pages[key].default
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export { pageIdentifierToPageComponent }
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
const pageIdentifierToPageComponent: Record<string, React.ComponentType> = {}
|
|
2
|
+
const pages = import.meta.glob('../views/**/*.tsx', { eager: true })
|
|
3
|
+
|
|
4
|
+
for (const key in pages) {
|
|
5
|
+
const identifier = key.replace('../views/', '').split('.')[0]
|
|
6
|
+
pageIdentifierToPageComponent[identifier] = (pages[key] as { default: React.ComponentType }).default
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export { pageIdentifierToPageComponent }
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import path from "path"
|
|
2
|
+
import resolve from "@rollup/plugin-node-resolve"
|
|
3
|
+
import commonjs from "@rollup/plugin-commonjs"
|
|
4
|
+
import babel from "@rollup/plugin-babel"
|
|
5
|
+
import alias from "@rollup/plugin-alias"
|
|
6
|
+
import importMetaGlob from "rollup-plugin-import-meta-glob"
|
|
7
|
+
import { rollup as deepkitPlugin } from "@thoughtbot/superglue/deepkit"
|
|
8
|
+
|
|
9
|
+
export default {
|
|
10
|
+
input: "app/javascript/application.tsx",
|
|
11
|
+
output: {
|
|
12
|
+
file: "app/assets/builds/application.js",
|
|
13
|
+
format: "esm",
|
|
14
|
+
inlineDynamicImports: true,
|
|
15
|
+
sourcemap: true
|
|
16
|
+
},
|
|
17
|
+
plugins: [
|
|
18
|
+
importMetaGlob(),
|
|
19
|
+
alias({
|
|
20
|
+
entries: [
|
|
21
|
+
{ find: "@javascript", replacement: path.resolve("app/javascript") },
|
|
22
|
+
{ find: "@views", replacement: path.resolve("app/views") }
|
|
23
|
+
]
|
|
24
|
+
}),
|
|
25
|
+
resolve({ extensions: [".ts", ".tsx", ".js", ".jsx"] }),
|
|
26
|
+
commonjs(),
|
|
27
|
+
babel({
|
|
28
|
+
babelHelpers: "bundled",
|
|
29
|
+
presets: [
|
|
30
|
+
["@babel/preset-react", { runtime: "automatic" }],
|
|
31
|
+
"@babel/preset-typescript"
|
|
32
|
+
],
|
|
33
|
+
extensions: [".ts", ".tsx", ".js", ".jsx"]
|
|
34
|
+
}),
|
|
35
|
+
...(process.env.NODE_ENV === 'production' ? [] : [deepkitPlugin()])
|
|
36
|
+
]
|
|
37
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import path from "path"
|
|
2
|
+
import resolve from "@rollup/plugin-node-resolve"
|
|
3
|
+
import commonjs from "@rollup/plugin-commonjs"
|
|
4
|
+
import babel from "@rollup/plugin-babel"
|
|
5
|
+
import alias from "@rollup/plugin-alias"
|
|
6
|
+
import importMetaGlob from "rollup-plugin-import-meta-glob"
|
|
7
|
+
|
|
8
|
+
export default {
|
|
9
|
+
input: "app/javascript/application.jsx",
|
|
10
|
+
output: {
|
|
11
|
+
file: "app/assets/builds/application.js",
|
|
12
|
+
format: "esm",
|
|
13
|
+
inlineDynamicImports: true,
|
|
14
|
+
sourcemap: true
|
|
15
|
+
},
|
|
16
|
+
plugins: [
|
|
17
|
+
importMetaGlob(),
|
|
18
|
+
alias({
|
|
19
|
+
entries: [
|
|
20
|
+
{ find: "@javascript", replacement: path.resolve("app/javascript") },
|
|
21
|
+
{ find: "@views", replacement: path.resolve("app/views") }
|
|
22
|
+
]
|
|
23
|
+
}),
|
|
24
|
+
resolve({ extensions: [".js", ".jsx"] }),
|
|
25
|
+
commonjs(),
|
|
26
|
+
babel({
|
|
27
|
+
babelHelpers: "bundled",
|
|
28
|
+
presets: [["@babel/preset-react", { runtime: "automatic" }]],
|
|
29
|
+
extensions: [".js", ".jsx"]
|
|
30
|
+
})
|
|
31
|
+
]
|
|
32
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import path from "path"
|
|
2
|
+
import resolve from "@rollup/plugin-node-resolve"
|
|
3
|
+
import commonjs from "@rollup/plugin-commonjs"
|
|
4
|
+
import babel from "@rollup/plugin-babel"
|
|
5
|
+
import alias from "@rollup/plugin-alias"
|
|
6
|
+
import importMetaGlob from "rollup-plugin-import-meta-glob"
|
|
7
|
+
|
|
8
|
+
export default {
|
|
9
|
+
input: "app/javascript/application.tsx",
|
|
10
|
+
output: {
|
|
11
|
+
file: "app/assets/builds/application.js",
|
|
12
|
+
format: "esm",
|
|
13
|
+
inlineDynamicImports: true,
|
|
14
|
+
sourcemap: true
|
|
15
|
+
},
|
|
16
|
+
plugins: [
|
|
17
|
+
importMetaGlob(),
|
|
18
|
+
alias({
|
|
19
|
+
entries: [
|
|
20
|
+
{ find: "@javascript", replacement: path.resolve("app/javascript") },
|
|
21
|
+
{ find: "@views", replacement: path.resolve("app/views") }
|
|
22
|
+
]
|
|
23
|
+
}),
|
|
24
|
+
resolve({ extensions: [".ts", ".tsx", ".js", ".jsx"] }),
|
|
25
|
+
commonjs(),
|
|
26
|
+
babel({
|
|
27
|
+
babelHelpers: "bundled",
|
|
28
|
+
presets: [
|
|
29
|
+
["@babel/preset-react", { runtime: "automatic" }],
|
|
30
|
+
"@babel/preset-typescript"
|
|
31
|
+
],
|
|
32
|
+
extensions: [".ts", ".tsx", ".js", ".jsx"]
|
|
33
|
+
})
|
|
34
|
+
]
|
|
35
|
+
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import { createRoot } from "react-dom/client";
|
|
3
|
-
import {
|
|
3
|
+
import { createApp, SaveResponse } from "@thoughtbot/superglue";
|
|
4
4
|
import { buildVisitAndRemote } from "./application_visit";
|
|
5
5
|
import { pageIdentifierToPageComponent } from "./page_to_page_mapping";
|
|
6
|
-
import {
|
|
6
|
+
import { Layout } from "./components";
|
|
7
7
|
|
|
8
8
|
declare global {
|
|
9
9
|
interface Window {
|
|
@@ -17,24 +17,30 @@ if (typeof window !== "undefined" && window.SUPERGLUE_INITIAL_PAGE_STATE) {
|
|
|
17
17
|
const location = window.location;
|
|
18
18
|
|
|
19
19
|
if (appEl) {
|
|
20
|
+
const { Provider, Outlet, ujs } = createApp({
|
|
21
|
+
// The base url prefixed to all calls made by the `visit`
|
|
22
|
+
// and `remote` thunks.
|
|
23
|
+
baseUrl: location.origin,
|
|
24
|
+
// The global var SUPERGLUE_INITIAL_PAGE_STATE is set by your erb
|
|
25
|
+
// template, e.g., index.html.erb
|
|
26
|
+
initialPage: window.SUPERGLUE_INITIAL_PAGE_STATE,
|
|
27
|
+
// The initial path of the page, e.g., /foobar
|
|
28
|
+
path: location.pathname + location.search + location.hash,
|
|
29
|
+
// Callback used to setup visit and remote
|
|
30
|
+
buildVisitAndRemote,
|
|
31
|
+
// Mapping between the page identifier to page component
|
|
32
|
+
mapping: pageIdentifierToPageComponent,
|
|
33
|
+
});
|
|
34
|
+
|
|
20
35
|
const root = createRoot(appEl);
|
|
21
36
|
root.render(
|
|
22
|
-
<
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
// The initial path of the page, e.g., /foobar
|
|
30
|
-
path={location.pathname + location.search + location.hash}
|
|
31
|
-
// Callback used to setup visit and remote
|
|
32
|
-
buildVisitAndRemote={buildVisitAndRemote}
|
|
33
|
-
// Callback used to setup the store
|
|
34
|
-
store={store}
|
|
35
|
-
// Mapping between the page identifier to page component
|
|
36
|
-
mapping={pageIdentifierToPageComponent}
|
|
37
|
-
/>
|
|
37
|
+
<div onClick={ujs.onClick} onSubmit={ujs.onSubmit}>
|
|
38
|
+
<Provider>
|
|
39
|
+
<Layout>
|
|
40
|
+
<Outlet />
|
|
41
|
+
</Layout>
|
|
42
|
+
</Provider>
|
|
43
|
+
</div>
|
|
38
44
|
);
|
|
39
45
|
}
|
|
40
46
|
});
|
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
import {
|
|
2
2
|
ApplicationRemote,
|
|
3
3
|
ApplicationVisit,
|
|
4
|
-
SuperglueStore,
|
|
5
4
|
BuildVisitAndRemote,
|
|
6
5
|
} from "@thoughtbot/superglue";
|
|
7
|
-
import { visit, remote } from "@thoughtbot/superglue/action_creators";
|
|
8
6
|
|
|
9
7
|
/**
|
|
10
8
|
* This function returns a wrapped visit and remote that will be used by UJS,
|
|
@@ -14,10 +12,11 @@ import { visit, remote } from "@thoughtbot/superglue/action_creators";
|
|
|
14
12
|
* You can customize both functions to your liking. For example, for a progress
|
|
15
13
|
* bar. This file also adds support for data-sg-remote.
|
|
16
14
|
*/
|
|
17
|
-
export const buildVisitAndRemote: BuildVisitAndRemote = (
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
15
|
+
export const buildVisitAndRemote: BuildVisitAndRemote = ({
|
|
16
|
+
navigateTo,
|
|
17
|
+
visit,
|
|
18
|
+
remote,
|
|
19
|
+
}) => {
|
|
21
20
|
const appRemote: ApplicationRemote = (path, { dataset, ...options } = {}) => {
|
|
22
21
|
/**
|
|
23
22
|
* You can make use of `dataset` to add custom UJS options.
|
|
@@ -32,27 +31,38 @@ export const buildVisitAndRemote: BuildVisitAndRemote = (
|
|
|
32
31
|
*
|
|
33
32
|
* This would be available as `sgHideProgress` on the dataset
|
|
34
33
|
*/
|
|
35
|
-
return
|
|
34
|
+
return remote(path, options).then((result) => {
|
|
35
|
+
if (result.hasError) {
|
|
36
|
+
const { response } = result;
|
|
37
|
+
|
|
38
|
+
if (response.status >= 400 && response.status < 500) {
|
|
39
|
+
window.location.href = "/400.html";
|
|
40
|
+
} else if (response.status >= 500) {
|
|
41
|
+
window.location.href = "/500.html";
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return result;
|
|
46
|
+
});
|
|
36
47
|
};
|
|
37
48
|
|
|
38
49
|
const appVisit: ApplicationVisit = (path, { dataset, ...options } = {}) => {
|
|
39
50
|
/**
|
|
40
51
|
* Do something before we make a request.
|
|
41
52
|
* e.g, show a [progress bar](https://thoughtbot.github.io/superglue/recipes/progress-bar/).
|
|
42
|
-
*
|
|
43
|
-
* Hint: you can access the current pageKey
|
|
44
|
-
* via `store.getState().superglue.currentPageKey`
|
|
45
53
|
*/
|
|
46
|
-
return
|
|
47
|
-
.
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
54
|
+
return visit(path, options)
|
|
55
|
+
.then((result) => {
|
|
56
|
+
if (result.hasError) {
|
|
57
|
+
const { response } = result;
|
|
58
|
+
|
|
59
|
+
if (response.status >= 400 && response.status < 500) {
|
|
60
|
+
window.location.href = "/400.html";
|
|
61
|
+
} else if (response.status >= 500) {
|
|
62
|
+
window.location.href = "/500.html";
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return result;
|
|
56
66
|
}
|
|
57
67
|
|
|
58
68
|
/**
|
|
@@ -61,19 +71,14 @@ export const buildVisitAndRemote: BuildVisitAndRemote = (
|
|
|
61
71
|
* This option overrides the `navigationAction` to allow a link click or
|
|
62
72
|
* a form submission to replace history instead of the usual push.
|
|
63
73
|
*/
|
|
64
|
-
const
|
|
74
|
+
const navigationAction = !!dataset?.sgReplace
|
|
65
75
|
? "replace"
|
|
66
|
-
:
|
|
67
|
-
|
|
68
|
-
action:
|
|
76
|
+
: result.navigationAction;
|
|
77
|
+
navigateTo(result.pageKey, {
|
|
78
|
+
action: navigationAction,
|
|
69
79
|
});
|
|
70
80
|
|
|
71
|
-
|
|
72
|
-
* Return the meta object, it's used for scroll restoration when
|
|
73
|
-
* handling the back button. You can skip returning, but Superglue
|
|
74
|
-
* will warn you about scroll restoration.
|
|
75
|
-
*/
|
|
76
|
-
return meta;
|
|
81
|
+
return result;
|
|
77
82
|
})
|
|
78
83
|
.finally(() => {
|
|
79
84
|
/**
|
|
@@ -81,40 +86,6 @@ export const buildVisitAndRemote: BuildVisitAndRemote = (
|
|
|
81
86
|
*
|
|
82
87
|
* This is where you hide a progress bar.
|
|
83
88
|
*/
|
|
84
|
-
})
|
|
85
|
-
.catch((err) => {
|
|
86
|
-
const response = err.response;
|
|
87
|
-
|
|
88
|
-
if (!response) {
|
|
89
|
-
/**
|
|
90
|
-
* This is for errors that are NOT from a HTTP request.
|
|
91
|
-
*
|
|
92
|
-
* Tooling like Sentry can capture console errors. If not, feel
|
|
93
|
-
* free to customize to send the error to your telemetry tool of choice.
|
|
94
|
-
*/
|
|
95
|
-
console.error(err);
|
|
96
|
-
return;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
if (response.ok) {
|
|
100
|
-
/**
|
|
101
|
-
* This is for errors that are from a HTTP request.
|
|
102
|
-
*
|
|
103
|
-
* If the response is OK, it must be an HTML body, we'll
|
|
104
|
-
* go to that locaton directly.
|
|
105
|
-
*/
|
|
106
|
-
window.location = response.url;
|
|
107
|
-
} else {
|
|
108
|
-
if (response.status >= 400 && response.status < 500) {
|
|
109
|
-
window.location.href = "/400.html";
|
|
110
|
-
return;
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
if (response.status >= 500) {
|
|
114
|
-
window.location.href = "/500.html";
|
|
115
|
-
return;
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
89
|
});
|
|
119
90
|
};
|
|
120
91
|
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import * as esbuild from 'esbuild'
|
|
2
|
+
import { esbuild as deepkitPlugin } from '@thoughtbot/superglue/deepkit'
|
|
3
|
+
|
|
4
|
+
const isWatch = process.argv.includes('--watch')
|
|
5
|
+
|
|
6
|
+
const buildOptions = {
|
|
7
|
+
entryPoints: [
|
|
8
|
+
'app/javascript/application.tsx',
|
|
9
|
+
],
|
|
10
|
+
bundle: true,
|
|
11
|
+
sourcemap: true,
|
|
12
|
+
format: 'esm',
|
|
13
|
+
outdir: 'app/assets/builds',
|
|
14
|
+
publicPath: '/assets',
|
|
15
|
+
plugins: process.env.NODE_ENV === 'production' ? [] : [deepkitPlugin()],
|
|
16
|
+
metafile: true,
|
|
17
|
+
conditions: process.env.NODE_ENV === 'production' ? ['production'] : [],
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
if (isWatch) {
|
|
21
|
+
const ctx = await esbuild.context(buildOptions)
|
|
22
|
+
await ctx.watch()
|
|
23
|
+
console.log('Watching for changes...')
|
|
24
|
+
} else {
|
|
25
|
+
const result = await esbuild.build(buildOptions)
|
|
26
|
+
console.log(await esbuild.analyzeMetafile(result.metafile))
|
|
27
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import * as esbuild from 'esbuild'
|
|
2
|
+
|
|
3
|
+
const isWatch = process.argv.includes('--watch')
|
|
4
|
+
|
|
5
|
+
const buildOptions = {
|
|
6
|
+
entryPoints: [
|
|
7
|
+
'app/javascript/application.tsx',
|
|
8
|
+
],
|
|
9
|
+
bundle: true,
|
|
10
|
+
sourcemap: true,
|
|
11
|
+
format: 'esm',
|
|
12
|
+
outdir: 'app/assets/builds',
|
|
13
|
+
publicPath: '/assets',
|
|
14
|
+
plugins: [],
|
|
15
|
+
metafile: true,
|
|
16
|
+
conditions: process.env.NODE_ENV === 'production' ? ['production'] : [],
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
if (isWatch) {
|
|
20
|
+
const ctx = await esbuild.context(buildOptions)
|
|
21
|
+
await ctx.watch()
|
|
22
|
+
console.log('Watching for changes...')
|
|
23
|
+
} else {
|
|
24
|
+
const result = await esbuild.build(buildOptions)
|
|
25
|
+
console.log(await esbuild.analyzeMetafile(result.metafile))
|
|
26
|
+
}
|