Skip to content

Commit

Permalink
Superglue install
Browse files Browse the repository at this point in the history
  • Loading branch information
jho406 committed Oct 8, 2023
1 parent 2a849be commit c341f48
Show file tree
Hide file tree
Showing 14 changed files with 258 additions and 7 deletions.
3 changes: 2 additions & 1 deletion Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,9 @@ end
gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]

gem "jsbundling-rails", "~> 1.2"

gem "cssbundling-rails", "~> 1.3"

gem 'sprockets-rails', :require => 'sprockets/railtie'
gem 'superglue', path: '/Users/johnyho/superglue/superglue_rails'

gem "form_props", "~> 0.0.3"
19 changes: 19 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
PATH
remote: /Users/johnyho/superglue/superglue_rails
specs:
superglue (0.50.0)
actionpack (>= 7.0.0)
form_props (>= 0.0.3)
props_template (>= 0.23.0)

GEM
remote: https://rubygems.org/
specs:
Expand Down Expand Up @@ -89,6 +97,10 @@ GEM
date (3.3.3)
erubi (1.12.0)
ffi (1.15.5)
form_props (0.0.3)
actionview (>= 7.0.0)
activesupport (>= 7.0.0)
props_template (>= 0.23.0)
globalid (1.2.1)
activesupport (>= 6.1)
i18n (1.14.1)
Expand Down Expand Up @@ -127,7 +139,12 @@ GEM
nio4r (2.5.9)
nokogiri (1.15.4-arm64-darwin)
racc (~> 1.4)
oj (3.16.1)
pg (1.5.4)
props_template (0.23.0)
actionview (>= 6.0.0)
activesupport (>= 6.0.0)
oj (>= 3.9)
public_suffix (5.0.3)
puma (4.3.12)
nio4r (~> 2.0)
Expand Down Expand Up @@ -214,6 +231,7 @@ DEPENDENCIES
byebug
capybara (>= 2.15)
cssbundling-rails (~> 1.3)
form_props (~> 0.0.3)
jbuilder (~> 2.7)
jsbundling-rails (~> 1.2)
listen (>= 3.0.5, < 3.2)
Expand All @@ -224,6 +242,7 @@ DEPENDENCIES
spring
spring-watcher-listen (~> 2.0.0)
sprockets-rails
superglue!
tzinfo-data
web-console (>= 3.3.0)
webdrivers
Expand Down
6 changes: 6 additions & 0 deletions app/javascript/actions.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { createAction } from '@reduxjs/toolkit'
import { SAVE_RESPONSE, BEFORE_VISIT, UPDATE_FRAGMENTS } from '@thoughtbot/superglue'

export const saveResponse = createAction(SAVE_RESPONSE)
export const beforeVisit = createAction(BEFORE_VISIT)
export const updateFragments = createAction(UPDATE_FRAGMENTS)
49 changes: 48 additions & 1 deletion app/javascript/application.js
Original file line number Diff line number Diff line change
@@ -1 +1,48 @@
// Entry point for the build script in your package.json
import React from 'react';
import thunk from 'redux-thunk';
import { Provider } from 'react-redux';
import { createRoot } from 'react-dom/client';
import { ApplicationBase } from '@thoughtbot/superglue';
import { buildVisitAndRemote } from './application_visit';
import { pageIdentifierToPageComponent } from './page_to_page_mapping';
import { buildStore } from './store'

class Application extends ApplicationBase {
mapping() {
return pageIdentifierToPageComponent;
}

visitAndRemote(navRef, store) {
return buildVisitAndRemote(navRef, store);
}

buildStore(initialState, { superglue, pages}) {
return buildStore(initialState, superglue, pages);
}
}

if (typeof window !== "undefined") {
document.addEventListener("DOMContentLoaded", function () {
const appEl = document.getElementById("app");
const location = window.location;

if (appEl) {
const root = createRoot(appEl);
root.render(
<Application
appEl={appEl}
// The base url prefixed to all calls made by the `visit`
// and `remote` thunks.
baseUrl={location.origin}
// The global var SUPERGLUE_INITIAL_PAGE_STATE is set by your erb
// template, e.g., index.html.erb
initialPage={window.SUPERGLUE_INITIAL_PAGE_STATE}
// The initial path of the page, e.g., /foobar
path={location.pathname + location.search + location.hash}
/>
);
}
});
}


65 changes: 65 additions & 0 deletions app/javascript/application_visit.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import { visit, remote } from '@thoughtbot/superglue/action_creators'

export function buildVisitAndRemote(ref, store) {
const appRemote = (...args) => {
return store.dispatch(remote(...args))
}

const appVisit = (...args) => {
// Do something before
// e.g, show loading state, you can access the current pageKey
// via store.getState().superglue.currentPageKey
let { action } = args

return store
.dispatch(visit(...args))
.then((meta) => {
// The assets fingerprints changed, instead of transitioning
// just go to the URL directly to retrieve new assets
if (meta.needsRefresh) {
window.location = meta.url
return
}

ref.current.navigateTo(meta.pageKey, {
action: meta.suggestedAction,
})

// always return meta
return meta
})
.finally(() => {
// Do something after
// e.g, hide loading state, you can access the changed pageKey
// via getState().superglue.currentPageKey
})
.catch((err) => {
const response = err.response

if (!response) {
console.error(err)
return
}

if (response.ok) {
// err gets thrown, but if the response is ok,
// it must be an html body that
// superglue can't parse, just go to the location
window.location = response.url
} else {
if (response.status >= 400 && response.status < 500) {
window.location = '/400.html'
return
}

if (response.status >= 500) {
window.location = '/500.html'
return
}
}
})
}

return { visit: appVisit, remote: appRemote }
}

12 changes: 12 additions & 0 deletions app/javascript/page_to_page_mapping.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// import your page component
// e.g import PostsEdit from '../views/posts/edit'


// Mapping between your props template to Component, you must add to this
// to register any new page level component you create. If you are using the
// scaffold, it will auto append the identifers for you.
//
// e.g {'posts/new': PostNew}
export const pageIdentifierToPageComponent = {
};

19 changes: 19 additions & 0 deletions app/javascript/slices/flash.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { createSlice } from '@reduxjs/toolkit'
import { saveResponse, beforeVisit } from '../actions'

export const flashSlice = createSlice({
name: 'flash',
initialState: {},
extraReducers: (builder) => {
builder.addCase(beforeVisit, (state, action) => {
return {}
})
builder.addCase(saveResponse, (state, action) => {
const { page } = action.payload;

return {
...state, ...page.slices.flash
}
})
}
})
15 changes: 15 additions & 0 deletions app/javascript/slices/pages.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { createSlice } from '@reduxjs/toolkit'
import { saveResponse, beforeVisit } from '../actions'

export const pagesSlice = createSlice({
name: 'pages',
// extraReducers: (builder) => {
// builder.addCase(beforeVisit, (state, action) => {
// const {currentPageKey} = action.payload
//
// const currentPage = draft[currentPageKey]
// delete currentPage.error
// })
// }
})

32 changes: 32 additions & 0 deletions app/javascript/store.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { configureStore } from '@reduxjs/toolkit'
import { pagesSlice } from "./slices/pages"
import { flashSlice } from "./slices/flash"
import {
BEFORE_VISIT,
BEFORE_FETCH,
BEFORE_REMOTE,
fragmentMiddleware
} from '@thoughtbot/superglue'

export const buildStore = (initialState, superglueReducer, supergluePagesReducer) => {

return configureStore({
preloadedState: initialState,
devTools: process.env.NODE_ENV !== 'production',
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware({
serializableCheck: {
ignoredActions: [BEFORE_VISIT, BEFORE_FETCH, BEFORE_REMOTE],
},
}).concat(fragmentMiddleware),
reducer: {
superglue: superglueReducer,
pages: (state, action) => {
const nextState = supergluePagesReducer(state, action)
return pagesSlice.reducer(nextState, action)
},
flash: flashSlice.reducer
},
});
};

7 changes: 7 additions & 0 deletions app/models/application_record.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
class ApplicationRecord < ActiveRecord::Base
def self.member_at(index)
offset(index).limit(1).first
end

def self.member_by(attr, value)
find_by(Hash[attr, value])
end
self.abstract_class = true
end
27 changes: 27 additions & 0 deletions app/views/layouts/application.json.props
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
path = request.format.json? ? param_to_search_path(params[:props_at]) : nil

json.data(search: path) do
yield json
end

json.component_identifier local_assigns[:virtual_path_of_template]
json.defers json.deferred!
json.fragments json.fragments!
json.assets [ asset_path('application.js') ]

if protect_against_forgery?
json.csrf_token form_authenticity_token
end

if path
json.action 'graft'
json.path search_path_to_camelized_param(path)
end

json.restore_strategy 'fromCacheAndRevisitInBackground'

json.rendered_at Time.now.to_i

json.slices do
json.flash flash.to_h
end
1 change: 1 addition & 0 deletions config/initializers/superglue.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
require "props_template/core_ext"
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"private": true,
"dependencies": {
"@reduxjs/toolkit": "^1.9.5",
"@thoughtbot/superglue": "^0.41.0",
"@thoughtbot/superglue": "^0.50.0",
"breakpoint-sass": "^3.0.0",
"esbuild": "^0.19.3",
"history": "^5.3.0",
Expand Down
8 changes: 4 additions & 4 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -129,10 +129,10 @@
redux-thunk "^2.4.2"
reselect "^4.1.8"

"@thoughtbot/superglue@^0.41.0":
version "0.41.0"
resolved "https://registry.yarnpkg.com/@thoughtbot/superglue/-/superglue-0.41.0.tgz#fa02bb38b4897798f95473ad493cbdf33356d074"
integrity sha512-jRbZd1lN9Qiw53pq5ADnJw39dZ8od4zeaXzusRc2IhcKzQY+bs0P4kid/EUvWWdSeAtLDPxpMdesRtCvnhkTlw==
"@thoughtbot/superglue@^0.50.0":
version "0.50.0"
resolved "https://registry.yarnpkg.com/@thoughtbot/superglue/-/superglue-0.50.0.tgz#db5fd185c0e4a34f23c77b6e406ce07bfb0d27a2"
integrity sha512-ngdGZq9PqRSYLpiLxv2MnbR8WZXOcPtAWjnbD9734L1QZdwCk53ESaOtCJauIHbQzXbWX6H8JdduqMOYajD52A==
dependencies:
abortcontroller-polyfill "^1.7.3"
babel-plugin-transform-react-remove-prop-types "^0.4.24"
Expand Down

0 comments on commit c341f48

Please sign in to comment.