Browse Source
* Asset pipeline * Hotwire * Dropping ActiveAdmin & AdminUser * Form setup sectionpull/750/head
baarkerlounger
2 years ago
committed by
GitHub
4 changed files with 107 additions and 0 deletions
@ -0,0 +1,43 @@ |
|||||||
|
--- |
||||||
|
parent: Architecture decisions |
||||||
|
--- |
||||||
|
|
||||||
|
# 015: Serving Frontend Assets (JS, CSS, Images) |
||||||
|
|
||||||
|
## Asset bundling (and JS transpilation) |
||||||
|
|
||||||
|
Originally we were using [Webpacker](https://github.com/rails/webpacker) to bundle and serve our front end assets as this was the default in Rails 6. This was effectively a wrapper around webpack intended to abstract away it's complexity and provide sane Rails defaults. It combined both bundling and serving the assets. |
||||||
|
|
||||||
|
However, since Rails 7, it's been deprecated by the Rails CORE team and it's javascript dependencies are no longer updated even for security fixes. As a result we decided we needed to move to one of the supported front end asset options. |
||||||
|
|
||||||
|
The primary options considered were: |
||||||
|
|
||||||
|
|
||||||
|
1. [Import maps](https://github.com/rails/importmap-rails) - Rails 7 default. Serve JS directly but do no transpiling so not suitable |
||||||
|
2. [JSBundling](https://github.com/rails/jsbundling-rails) - Rails recommended |
||||||
|
- With [ESBuild](https://esbuild.github.io/) - fast and does some transpiling but [doesn't support ES5/IE11](https://github.com/communitiesuk/submit-social-housing-lettings-and-sales-data/pull/203) |
||||||
|
- With [Rollup](https://www.rollupjs.org/guide/en/) - similar to ESBuild, node rather than Go based, doesn't have the big speed benefits |
||||||
|
- With [Webpack](https://webpack.js.org/) - rather than the old approach of using Webpacker as a opinionated wrapper around webpack, this approach uses webpack directly. |
||||||
|
3. [Shakapacker](https://github.com/shakacode/shakapacker) - the "official" community maintained fork of Webpacker 6 RC. Requires upgrading current install since breaking changes happened between Webpacker 5 & 6 |
||||||
|
4. [Vite](https://vite-ruby.netlify.app/) - Webpack alternative |
||||||
|
|
||||||
|
We need to consider that we had to support Internet Explorer 11/ES5 and that we have ES6 dependencies (Govuk frontend and Stimulus/Turbo). |
||||||
|
|
||||||
|
This ruled out Import Maps as that approach doesn't support transpilation at all. It also ruled out using ESBuild as that supported some transpilation but not to the level we need. |
||||||
|
|
||||||
|
Shakapacker is a continuation of the previous Webpacker approach. We explored seeing whether this would be the easiest path but Webpacker v5 -> v6 release candidate was a relatively significant breaking change and with the work required to update and this approach no longer being the favoured one upstream it seemed more worthwhile to make the bigger change to JSBundling directly. |
||||||
|
|
||||||
|
Ultimately we moved to using JSBundling with Webpack and Babel. This exposes the webpack config directly in a way that is better documented upstream. |
||||||
|
|
||||||
|
This change was made here: https://github.com/communitiesuk/submit-social-housing-lettings-and-sales-data/pull/392 |
||||||
|
|
||||||
|
We also use Webpack to bundle our CSS and Image assets. |
||||||
|
|
||||||
|
## Asset Pipeline |
||||||
|
|
||||||
|
JSBundling with Webpack handles the asset bundling part of what Webpacker used to do but still requires the asset pipeline to deliver it. The choices here are: |
||||||
|
|
||||||
|
- [Sprockets](https://github.com/rails/sprockets-rails) - the original Rails asset pipeline and current default |
||||||
|
- [Propshaft](https://github.com/rails/propshaft) - a more recent alternative that assumes most people will be using a node based JS bundler anyway and so can take a simpler approach than Sprockets by doing less |
||||||
|
|
||||||
|
Given that our use case matches Propshaft quite closely and it's intended to replace Sprockets as the default for Rails at some point in the future we choose to use Propshaft. |
@ -0,0 +1,17 @@ |
|||||||
|
--- |
||||||
|
parent: Architecture decisions |
||||||
|
--- |
||||||
|
|
||||||
|
# 015: Hotwire & Internet Explorer |
||||||
|
|
||||||
|
Initially we intended to use Hotwire (Stimulus and Turbo). Stimulus as our "minimal javascript framework", Turbo to provide an "SPA-like" experience. However, despite now being deprecated by Microsoft, a significant proportion of our users are still using Internet Explorer 10/11 to access the service (~30% based on 2021 server logs) and so we needed to support Internet Explorer >= 10 also for the time being. This presented a problem as neither Stimulus nor Turbo support Internet Explorer and upstream have indicated there is [no interest in adding support](https://github.com/hotwired/hotwire-rails/issues/32). |
||||||
|
|
||||||
|
To address this we first attempted to transpile the Stimulus and Turbo libraries from ES6 down to ES5 with Babel and add any required polyfills. |
||||||
|
|
||||||
|
For **Stimulus** we were able to do this and are continuing to use it. This is achieved by: |
||||||
|
|
||||||
|
- Adding the [@Stimulus/Polyfills](https://www.npmjs.com/package/@stimulus/polyfills) package to our [package.json](https://github.com/communitiesuk/submit-social-housing-lettings-and-sales-data/blob/main/package.json#L12) |
||||||
|
- Adding the StimulusJS NPM package path to our [webpack config](https://github.com/communitiesuk/submit-social-housing-lettings-and-sales-data/blob/main/webpack.config.js#L23) rules to be transpiled |
||||||
|
- Adding the required Babel plugins to our [Babel config](https://github.com/communitiesuk/submit-social-housing-lettings-and-sales-data/blob/main/babel.config.js#L34) |
||||||
|
|
||||||
|
For **Turbo** the same approach was attempted but proved [unsuccessful](https://github.com/communitiesuk/submit-social-housing-lettings-and-sales-data/pull/430). As a result we decided to [remove Turbo](https://github.com/communitiesuk/submit-social-housing-lettings-and-sales-data/pull/406) until we can drop support for Internet Explorer. This does have a perceptible impact on UX/speed but provides the most browser compatibility. |
@ -0,0 +1,19 @@ |
|||||||
|
--- |
||||||
|
parent: Architecture decisions |
||||||
|
--- |
||||||
|
|
||||||
|
# 017: Dropping ActiveAdmin & The Admin User class |
||||||
|
|
||||||
|
Originally ActiveAdmin was used as a quick way to spin up a panel that developers or support users could use to check or amend data. An AdminUser class/model separate from the User class was created specifically for access to this (see ADR-010). |
||||||
|
|
||||||
|
Testing ActiveAdmin with support users found that it was not useable for them. The main problems were: |
||||||
|
|
||||||
|
- Data values were largely raw database values, not translated to value strings (which don't necessarily have a 1-1 mapping but might depend on the form year etc) |
||||||
|
- The default design was not as accessible as the rest of the service |
||||||
|
- The default design was very visually different and doesn't match the Govuk design patterns |
||||||
|
|
||||||
|
We briefly explored whether the ActiveAdmin interface could be themed to [match the Govuk design system and be more accessible](https://github.com/communitiesuk/submit-social-housing-lettings-and-sales-data/pull/397) but that experiment itself relied on unmaintained dependencies. Overall testing suggested making ActiveAdmin maintainable and suitable for support users was likely to be more work than building those functions into the service. |
||||||
|
|
||||||
|
As a result we removed [ActiveAdmin and the AdminUser class](https://github.com/communitiesuk/submit-social-housing-lettings-and-sales-data/pull/611). This helped simplify our Devise setup (only 1 authenticable model), and also helped slim down dependencies and simplify our asset setup since we know longer need to ship jQuery etc. |
||||||
|
|
||||||
|
Support user functionality like adding, editing, activating or deactivating users, organisations, schemes and logs are now built into the service itself. In general this re-uses the same views data coordinators already have for these functions, it just lets them act on all organisations rather than the single organisation the user belongs to. |
@ -0,0 +1,28 @@ |
|||||||
|
--- |
||||||
|
parent: Architecture decisions |
||||||
|
--- |
||||||
|
|
||||||
|
# 018: Setup this log section |
||||||
|
|
||||||
|
Originally the "Setup this lettings log" section of the form was included in the JSON form definition for each form year, the same as any other section, because it mostly had the same behaviour as all other sections. It could be treated as pure configuration like the rest of the form. |
||||||
|
|
||||||
|
This increasingly stopped being true as further design requirements were added: |
||||||
|
|
||||||
|
- The setup section needs to be completed first unlike all other sections which can be completed in any order |
||||||
|
- Changing answers in the setup section potentially invalidates large parts of the rest of the form |
||||||
|
- The setup question started including questions that needed to know a lot more about the application context than was reasonable for pure config in order to support Support User journeys (e.g. some questions should only show for specific user types, some answer options should only show for specific organisations etc) |
||||||
|
- This section can't easily change between form years as other sections can as it's essential to determining what questions to show next (effectively this section is equivalent to the ~8 different form links the old system had) |
||||||
|
|
||||||
|
The amount of application context needed to make it work is what ultimately drove the decision to make the section out of config and into code since trying to include that in JSON would require the JSON to be even more tightly coupled to the code than it already is and would dramatically increase the complexity of the JSON "DSL". |
||||||
|
|
||||||
|
Instead the setup section is now composed of coded Ruby class in `app/models/form/setup`. |
||||||
|
|
||||||
|
It still has all the same components as before: |
||||||
|
- Section |
||||||
|
- Subsection |
||||||
|
- Pages |
||||||
|
- Questions |
||||||
|
|
||||||
|
And each of these are subclasses of the generic class, which can have more application specific logic included. |
||||||
|
|
||||||
|
Now, when the `FormHandler` singleton class instantiates each form, the `Form` class constructor also first instantiates the setup section (which sets up it's own subsections, which in turn setup their own pages etc), and then sets up the rest of the form sections, subsections etc. The end result is that the `FormHandler` still holds a reference to each form, and each form still includes the setup section as it did before when the setup section was included in the JSON form definition, just that now it's easier to include more custom behaviour in that section. |
Loading…
Reference in new issue