From 8723ce7f7a82f4339d202c1997f853ddc96110fb Mon Sep 17 00:00:00 2001 From: Alex Turchyn Date: Wed, 16 Sep 2026 02:08:13 +0300 Subject: [PATCH] migrate to turbo 8 --- app/javascript/application.js | 6 +- app/javascript/lib/turbo_instant_click.js | 98 ----------------------- app/views/layouts/application.html.erb | 2 + app/views/shared/_navbar.html.erb | 2 +- app/views/shared/_navbar_buttons.html.erb | 2 +- config/webpack/webpack.config.js | 8 ++ package.json | 5 +- yarn.lock | 66 ++++++++++++--- 8 files changed, 69 insertions(+), 120 deletions(-) delete mode 100644 app/javascript/lib/turbo_instant_click.js diff --git a/app/javascript/application.js b/app/javascript/application.js index d95cc4676..86ce6a103 100644 --- a/app/javascript/application.js +++ b/app/javascript/application.js @@ -1,5 +1,4 @@ -import '@hotwired/turbo' -import { encodeMethodIntoRequestBody } from '@hotwired/turbo-rails/app/javascript/turbo/fetch_requests' +import '@hotwired/turbo-rails' import { createApp, reactive } from 'vue' import TemplateBuilder from './template_builder/builder' @@ -69,9 +68,7 @@ import OpenModalMobile from './elements/open_modal_mobile' import HistoryBack from './elements/history_back' import DatePlaceholder from './elements/date_placeholder' -import * as TurboInstantClick from './lib/turbo_instant_click' -TurboInstantClick.start() document.addEventListener('turbo:before-cache', () => { window.flash?.remove() @@ -83,7 +80,6 @@ document.addEventListener('keyup', (e) => { } }) -document.addEventListener('turbo:before-fetch-request', encodeMethodIntoRequestBody) document.addEventListener('turbo:before-fetch-request', (event) => { event.detail.fetchOptions.headers['X-Turbo'] = 'true' }) diff --git a/app/javascript/lib/turbo_instant_click.js b/app/javascript/lib/turbo_instant_click.js deleted file mode 100644 index 2a021e644..000000000 --- a/app/javascript/lib/turbo_instant_click.js +++ /dev/null @@ -1,98 +0,0 @@ -const requestCache = new Map() -const cacheTtl = 10 * 1000 - -function isPreloadable (linkElement) { - const href = linkElement.getAttribute('href') - - if (!href || href === '#' || linkElement.dataset.turbo === 'false' || linkElement.dataset.prefetch === 'false') { - return - } - - if (linkElement.origin !== document.location.origin) { - return - } - - if (!['http:', 'https:'].includes(linkElement.protocol)) { - return - } - - if (linkElement.pathname + linkElement.search === document.location.pathname + document.location.search) { - return - } - - if (linkElement.dataset.turboMethod && linkElement.dataset.turboMethod !== 'get') { - return - } - - return true -} - -function mouseoverListener (event) { - let linkElement - - if (event.target.tagName === 'A') { - linkElement = event.target - } else { - linkElement = event.target.closest('a') - } - - if (!linkElement) { - return - } - - if (!isPreloadable(linkElement)) { - return - } - - const url = linkElement.getAttribute('href') - const loc = new URL(url, location.protocol + '//' + location.host) - const absoluteUrl = loc.toString() - - const cached = requestCache.get(absoluteUrl) - - if (cached && cached.ttl > new Date()) { - return - } - - const requestOptions = { - credentials: 'same-origin', - headers: { Accept: 'text/html, application/xhtml+xml', 'VND.PREFETCH': 'true', 'X-Turbo': 'true' }, - method: 'GET', - redirect: 'follow' - } - - if (linkElement.dataset.turboFrame && linkElement.dataset.turboFrame !== '_top') { - requestOptions.headers['Turbo-Frame'] = linkElement.dataset.turboFrame - } else if (linkElement.dataset.turboFrame !== '_top') { - const turboFrame = linkElement.closest('turbo-frame') - - if (turboFrame && turboFrame.getAttribute('target') !== '_top') { - requestOptions.headers['Turbo-Frame'] = turboFrame.id - } - } - - requestCache.set(absoluteUrl, { request: fetch(absoluteUrl, requestOptions), ttl: new Date(new Date().getTime() + cacheTtl) }) -} - -function turboBeforeFetchRequest (event) { - if (event.target.tagName !== 'FORM' && event.detail.fetchOptions.method === 'GET') { - const cached = requestCache.get(event.detail.url.toString()) - - if (cached && cached.ttl > new Date()) { - event.detail.response = cached.request - } - } - - requestCache.clear() -} - -function start () { - if (!window.turboInstantClickEnabled) { - document.addEventListener('turbo:before-fetch-request', turboBeforeFetchRequest) - document.addEventListener('mouseover', mouseoverListener, { capture: true, passive: true }) - } - - window.turboInstantClickEnabled = true -} - -export { start } diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb index 2f74d1427..4b4acb14d 100644 --- a/app/views/layouts/application.html.erb +++ b/app/views/layouts/application.html.erb @@ -7,6 +7,8 @@ <% end %> <%= csrf_meta_tags %> + + <% if ENV['ROLLBAR_CLIENT_TOKEN'] %> <%= javascript_pack_tag 'rollbar', 'application', defer: true %> diff --git a/app/views/shared/_navbar.html.erb b/app/views/shared/_navbar.html.erb index 6725711ea..a21fbfad0 100644 --- a/app/views/shared/_navbar.html.erb +++ b/app/views/shared/_navbar.html.erb @@ -42,7 +42,7 @@ <% if !Docuseal.demo? && can?(:manage, EncryptedConfig) %>
  • - <%= link_to Docuseal.multitenant? ? console_redirect_index_path : Docuseal::CONSOLE_URL, data: { prefetch: false }, class: 'flex items-center' do %> + <%= link_to Docuseal.multitenant? ? console_redirect_index_path : Docuseal::CONSOLE_URL, data: { turbo_prefetch: false }, class: 'flex items-center' do %> <%= svg_icon('terminal', class: 'w-5 h-5 flex-shrink-0 stroke-2') %> <%= t('console') %> <% end %> diff --git a/app/views/shared/_navbar_buttons.html.erb b/app/views/shared/_navbar_buttons.html.erb index f86926993..056f3397c 100644 --- a/app/views/shared/_navbar_buttons.html.erb +++ b/app/views/shared/_navbar_buttons.html.erb @@ -1,7 +1,7 @@ <% if signed_in? && current_user != true_user %> <%= render 'shared/test_alert' %> <% elsif request.path.starts_with?('/settings') %> - <%= link_to "#{Docuseal::CLOUD_URL}/sign_up?#{{ redir: "#{Docuseal::CONSOLE_URL}/on_premises" }.to_query}", class: 'hidden md:inline-flex btn btn-warning btn-sm', data: { prefetch: false } do %> + <%= link_to "#{Docuseal::CLOUD_URL}/sign_up?#{{ redir: "#{Docuseal::CONSOLE_URL}/on_premises" }.to_query}", class: 'hidden md:inline-flex btn btn-warning btn-sm', data: { turbo_prefetch: false } do %> <%= t('upgrade') %> <% end %> diff --git a/config/webpack/webpack.config.js b/config/webpack/webpack.config.js index cf5ba5fcc..f5445f2b3 100644 --- a/config/webpack/webpack.config.js +++ b/config/webpack/webpack.config.js @@ -47,6 +47,14 @@ configs.module = merge({ test: /dynamic_styles\.scss$/, use: ['css-loader', 'postcss-loader', 'sass-loader'] }, + { + test: /@hotwired\/turbo\/dist/, + loader: 'string-replace-loader', + options: { + search: 'const PREFETCH_DELAY = 100;', + replace: 'const PREFETCH_DELAY = 0;' + } + }, { test: /\.vue$/, use: [{ diff --git a/package.json b/package.json index c0b6144cf..68fc8bf46 100644 --- a/package.json +++ b/package.json @@ -10,8 +10,8 @@ "@codemirror/lang-html": "^6.4.9", "@eid-easy/eideasy-widget": "^2.171.0", "@github/catalyst": "^2.0.0-beta", - "@hotwired/turbo": "https://github.com/docusealco/turbo#main", - "@hotwired/turbo-rails": "^7.3.0", + "@hotwired/turbo": "^8.0.23", + "@hotwired/turbo-rails": "^8.0.23", "@specious/htmlflow": "^1.1.0", "@tabler/icons-vue": "^2.47.0", "@tiptap/core": "^3.19.0", @@ -53,6 +53,7 @@ "shakapacker": "9.5.0", "signature_pad": "^4.1.5", "snarkdown": "^2.0.0", + "string-replace-loader": "^3.3.0", "style-loader": "^4.0.0", "tailwindcss": "^3.4.17", "terser-webpack-plugin": "5.3.16", diff --git a/yarn.lock b/yarn.lock index 71b9dddaa..a1aff1be6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1206,17 +1206,18 @@ resolved "https://registry.yarnpkg.com/@github/catalyst/-/catalyst-2.0.0-beta.tgz#a0aef206cee56902d9354d12ff1e92925b5f9063" integrity sha512-E2avZZ+rcbm7E3ou7lXrB8SfcaA+3CQs3YwoYzoOyfsLOr+57N6N+KJcU/ESUsZqC4ve1PKvdG5TrOK8Q9MB6w== -"@hotwired/turbo-rails@^7.3.0": - version "7.3.0" - resolved "https://registry.yarnpkg.com/@hotwired/turbo-rails/-/turbo-rails-7.3.0.tgz#422c21752509f3edcd6c7b2725bbe9e157815f51" - integrity sha512-fvhO64vp/a2UVQ3jue9WTc2JisMv9XilIC7ViZmXAREVwiQ2S4UC7Go8f9A1j4Xu7DBI6SbFdqILk5ImqVoqyA== +"@hotwired/turbo-rails@^8.0.23": + version "8.0.23" + resolved "https://registry.yarnpkg.com/@hotwired/turbo-rails/-/turbo-rails-8.0.23.tgz#7a84ad041cb0f3e5d9ff97d1a1f0291550a93fc9" + integrity sha512-iBILwda3qmQC7FYM70+4s6kEQ7Fx9dJ6+yGxjPyrz9a5JDx1+y7OAA5TA7GGVOZJoicMLrKGdFDNorl40X35lw== dependencies: - "@hotwired/turbo" "^7.3.0" - "@rails/actioncable" "^7.0" + "@hotwired/turbo" "^8.0.23" + "@rails/actioncable" ">=7.0" -"@hotwired/turbo@^7.3.0", "@hotwired/turbo@https://github.com/docusealco/turbo#main": - version "7.3.0" - resolved "https://github.com/docusealco/turbo#64d286a14b0d11383719a9a09852a775863d621a" +"@hotwired/turbo@^8.0.23": + version "8.0.23" + resolved "https://registry.yarnpkg.com/@hotwired/turbo/-/turbo-8.0.23.tgz#a6eebc9ab4a5faadae265a4cbec8cfcb5731e77c" + integrity sha512-GZ7cijxEZ6Ig71u7rD6LHaRv/wcE/hNsc+nEfiWOkLNqUgLOwo5MNGWOy5ZV9ZUDSiQx1no7YxjTNnT4O6//cQ== "@humanwhocodes/config-array@^0.11.8": version "0.11.8" @@ -1731,10 +1732,10 @@ resolved "https://registry.yarnpkg.com/@polka/url/-/url-1.0.0-next.21.tgz#5de5a2385a35309427f6011992b544514d559aa1" integrity sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g== -"@rails/actioncable@^7.0": - version "7.0.4" - resolved "https://registry.yarnpkg.com/@rails/actioncable/-/actioncable-7.0.4.tgz#70a3ca56809f7aaabb80af2f9c01ae51e1a8ed41" - integrity sha512-tz4oM+Zn9CYsvtyicsa/AwzKZKL+ITHWkhiu7x+xF77clh2b4Rm+s6xnOgY/sGDWoFWZmtKsE95hxBPkgQQNnQ== +"@rails/actioncable@>=7.0": + version "7.2.302" + resolved "https://registry.yarnpkg.com/@rails/actioncable/-/actioncable-7.2.302.tgz#f074632ee55aa1b5b16cd2be094b42981a71c322" + integrity sha512-9JOPzUb7RCqIEWeoE78mPFd71fzyJ25LjeMzD45zQ75f41ca7BsgQVqiyrIuxDZ1yyZ4PdyxCMZF0KJlJ9qX0g== "@remirror/core-constants@3.0.0": version "3.0.0" @@ -2411,6 +2412,13 @@ ajv-formats@^2.1.1: dependencies: ajv "^8.0.0" +ajv-formats@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/ajv-formats/-/ajv-formats-3.0.1.tgz#3d5dc762bca17679c3c2ea7e90ad6b7532309578" + integrity sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ== + dependencies: + ajv "^8.0.0" + ajv-keywords@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-5.1.0.tgz#69d4d385a4733cdbeab44964a1170a88f87f0e16" @@ -2438,6 +2446,16 @@ ajv@^8.0.0, ajv@^8.9.0: require-from-string "^2.0.2" uri-js "^4.2.2" +ajv@^8.20.0: + version "8.20.0" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.20.0.tgz#304b3636add88ba7d936760dd50ece006dea95f9" + integrity sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA== + dependencies: + fast-deep-equal "^3.1.3" + fast-uri "^3.0.1" + json-schema-traverse "^1.0.0" + require-from-string "^2.0.2" + ansi-html-community@^0.0.8: version "0.0.8" resolved "https://registry.yarnpkg.com/ansi-html-community/-/ansi-html-community-0.0.8.tgz#69fbc4d6ccbe383f9736934ae34c3f8290f1bf41" @@ -3929,6 +3947,11 @@ fast-levenshtein@^2.0.6: resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== +fast-uri@^3.0.1: + version "3.1.8" + resolved "https://registry.yarnpkg.com/fast-uri/-/fast-uri-3.1.8.tgz#f7db8d942e20eead3cfe93b0beeb4eb0169e938b" + integrity sha512-GZMtZUTNRpOVIECoXwLNZS5xUGE+mVNbTB8h/7Rwh2TFWcBQiPzTgyZi05BF9UMZKkLJv8XBRJTlU7zg8+ZfMg== + fastest-levenshtein@^1.0.12: version "1.0.16" resolved "https://registry.yarnpkg.com/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz#210e61b6ff181de91ea9b3d1b84fdedd47e034e5" @@ -6334,6 +6357,16 @@ sass@^1.62.1: immutable "^4.0.0" source-map-js ">=0.6.2 <2.0.0" +schema-utils@^4: + version "4.5.0" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-4.5.0.tgz#aaf8d588bd2b19511175175a5222baef648c009c" + integrity sha512-zJlMCZ0cAR5p/Y4oVpRoqioDMJcGxaXRrQ/4rP4WyR84vc5z/DolXdbvXeDpTwbtocDFr2rhPqHPErDCUtz2kA== + dependencies: + "@types/json-schema" "^7.0.15" + ajv "^8.20.0" + ajv-formats "^3.0.1" + ajv-keywords "^5.1.0" + schema-utils@^4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-4.0.1.tgz#eb2d042df8b01f4b5c276a2dfd41ba0faab72e8d" @@ -6649,6 +6682,13 @@ statuses@~2.0.1, statuses@~2.0.2: resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.2.tgz#8f75eecef765b5e1cfcdc080da59409ed424e382" integrity sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw== +string-replace-loader@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/string-replace-loader/-/string-replace-loader-3.3.0.tgz#db560185471d4be1566321fa736669a4667cf3dc" + integrity sha512-AZ3y7ktSHhd/Ebipczkp6vdfp01d2kQVwFujCGAgmogTB8t4dRhbsRGDKnyZAYqBbIA9QW7+D/IsACVJOOpcBg== + dependencies: + schema-utils "^4" + "string-width-cjs@npm:string-width@^4.2.0": version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"