Feature #39111
closedEnable Asset Pipeline Integration using Propshaft
Added by Takashi Kato about 1 year ago. Updated 11 days ago.
0%
Description
This patch enables the Asset Pipeline in Redmine, assuming you have upgraded to Rails 7(#36320).
Until Rails 6.1, Sprockets was a prerequisite for using the Asset Pipeline. However, starting from Rails 7, Propshaft has been introduced as an alternative option.
While Propshaft offers fewer features compared to Sprockets, it boasts a smaller codebase and greater clarity in its operations (eliminating the need for a JavaScript runtime). Additionally, manifest files are no longer necessary during development.
Key benefits of using Propshaft include:
- The ability to append file digests to file names instead of Rails3 stytle cache-busting approach involving query strings at the end of assets (expected to enhance cache hit rates).
- Support for tasks like copying plugin assets to the public directory each time Redmine starts.
- Compatibility with Turbo, which is almost mandatory in Rails 7 and later. (Note that Rails 7 and later deprecate rails-ujs, the current Redmine dependency.)
To address potential challenges associated with introducing Propshaft, we have extended its functionality in the following ways:
- We've made it possible for Propshaft to handle Redmine plugin and theme assets without requiring modification(If we use propshaft in default, we will need to modify the links to other assets in stylesheets.).
- We've ensured that introducing Asset Pipeline does not necessitate rewriting existing stylesheets, thus avoiding major incompatibilities with Redmine themes.
- In a production environment, rather than manually running the rails asset:precompile command before starting Rails, we now automatically check for asset updates and run precompilation as needed. (You can disable this automatic execution by setting config.assets.redmine_detect_update to false in
config/environments/production.rb
).
Files
Related issues
Updated by Dmitry Lisichkin about 1 year ago
Hello. Sorry for long response.
Am I right that your idea is about using propshaft without other tools (without compilation)?
In my work I start from another side - compilation with old good sprockets as digest generator.
Updated by Dmitry Lisichkin about 1 year ago
And after all I can say that your way can be much simplier because of using tools like webpack or other requires many changes in existed js files of redmine.
For example application.js
is just a big helper that in propper way should be splitted to many small libraries.
Another problem is a huge usage of js.erb
files that directly call functions from application.js
and other js files.
Updated by Dmitry Lisichkin about 1 year ago
One other problem that we have on our installation - many existed themes and plugins assumed that redmine assets available on root of public directory (not in assets subdirectory), I see a lot of hardcoded pathes in js
and css
that use absolute and relative paths to the root of redmine hosts.
As result I still have old mechanic with copying assets to root of public directory for backward compability.
Good alternative is usage of old behaviour for plugin_name/assets/*
and use new behaviour for some other directories like plugin_name/app/assets/*
.
Updated by Marius BĂLTEANU 11 months ago
- Target version set to 6.0.0
Let’s discuss this for Redmine 6.0.0.
Updated by Marius BĂLTEANU 11 months ago
Takashi Kato, this is a very nice improvement, thank you for your hard working on this.
I made some quick tests now and I didn't find any major problem, I was able to use the current trunk version of Redmine with all three patches applied and two plugins:- additionals: https://github.com/alphanodes/additionals
- redmine_issue_dynamic_edit: https://github.com/Ilogeek/redmine_issue_dynamic_edit
Also, I've quickly created a fourth patch (attached) that removes the manually hardcoded rails-ujs
library from jquery-3.6.1-ui-1.13.2-ujs-7.1.2.js
and uses the one provided by the actionview
gem, it's working very well.
Some notes:
1. Task bin/rails redmine:plugins:assets
no longer works:
bin/rails aborted! NoMethodError: undefined method `mirror_assets' for Redmine::PluginLoader:Class Redmine::PluginLoader.mirror_assets(name) ^^^^^^^^^^^^^^ /work/lib/tasks/redmine.rake:164:in `block (3 levels) in <top (required)>'
Should we adapt it to generate the assets for a specific plugin or completely drop it.
2. For Redmine core assets, as next improvement after integrating these patches, I would like to move our existing assets to app/assets
for the sake of consistency with Rails default structure and to not provide in the public folder two folders, the "source" assets and the actual assets (generated with Asset Pipeline). I'm aware that more changes are required, but I do not see a real problem to include all of them in 6.0.0.
3. Dmitry Lisichkin has a point in #note-3, but at the same time, I think the complexity to keep both behaviours for plugins do not worth it. I'm even in favour to move the plugin assets in "app/assets" to force plugins to use the correct way and also to stick to the Rails structure. The changes to adapt a plugin to this breaking change are minimal.
Updated by Marius BĂLTEANU 11 months ago
Updated by Takashi Kato 11 months ago
- File 0001v2-Add-propshaft-to-enable-asset-pipeline.patch 0001v2-Add-propshaft-to-enable-asset-pipeline.patch added
Marius BĂLTEANU
Thank you for your review and positive feedback.
I agree with matching the behavior of the plugin to Railsway as much as possible.
I've updated the 0001-patch to fix the bug that prevents reloading when some assets are modified in development mode(the name of instance variable was incorrect).
Dmitry Lisichkin
You're correct to point out that if an asset is hard-coded in JavaScript under the 'public' directory, that section of the JavaScript requires modification when applying this patch. However, such path definitions can also cause issues like incorrect cache retrieval during version upgrades.
Modifying the image retrieval method in line with the Asset Pipeline introduction could address this.
"js.erb" files in the app/views directory are returned by the controller and not handled with the asset pipeline.
While Ruby on Rails has recently seen the role of "js.erb" replaced by Hotwire's Turbo Streams, that's distinct from the changes under discussion here.
Updated by Marius BĂLTEANU 10 months ago
- Assignee set to Marius BĂLTEANU
I've committed the first 4 patches in order to enable the asset pipeline. I'm aware that it's a big and potentially breaking change so I wanted to integrate this as soon as possible in order to have enough time to get feedback from everyone involved.
I'm going to make more changes in the following days, my goal is to match as much as possible the rails recommended directory structure with minimal changes for plugins developers.
Updated by Marius BĂLTEANU 10 months ago
Takashi Kato, do you have any clue why the following test fails on Redmine CI, but not on local environment?
Failure: Redmine::AssetPathTest#test_asset_path_size [test/unit/lib/redmine/asset_path_test.rb:31]: Expected: 2 Actual: 3 bin/rails test test/unit/lib/redmine/asset_path_test.rb:30
Updated by Dmitry Lisichkin 10 months ago
Marius BĂLTEANU wrote in #note-9:
Takashi Kato, do you have any clue why the following test fails on Redmine CI, but not on local environment?
[...]
Can it be .svn
directory?
Updated by Marius BĂLTEANU 10 months ago
Dmitry Lisichkin wrote in #note-10:
Marius BĂLTEANU wrote in #note-9:
Takashi Kato, do you have any clue why the following test fails on Redmine CI, but not on local environment?
[...]
Can it be
.svn
directory?
It could be, I've added some test code to see what asset_path
contains, now we need to wait for the CI to run.
Updated by Marius BĂLTEANU 10 months ago
Fix the failing test in r22641.
Dmitry Lisichkin, thanks for your advise!
Updated by Takashi Kato 10 months ago
Marius BĂLTEANU
Thank you for the detailed review and merge!!
Dmitry Lisichkin
I didn't realize it! Thanks!
Updated by Marius BĂLTEANU 10 months ago
- Subject changed from Asset Pipeline Integration in Redmine for Rails 7 without modifying existing themes to Enable Asset Pipeline Integration
Updated by Marius BĂLTEANU 10 months ago
- Related to Patch #40137: Jstoolbar help files should import images from the asset pipeline added
Updated by Marius BĂLTEANU 10 months ago
- Subject changed from Enable Asset Pipeline Integration to Enable Asset Pipeline Integration using Propshaft
I changed all CSS files from public directory to use absolute url to images which is Propshaft expected format.
Takashi Kato, you're implementation Redmine::Asset.new
is very useful and I think we should keep it for at least 1 major version in order to give plugins developer time to update their files, but with a deprecation message in the logs. What do you think?
Also, I've added a new issue that we need to fix #40137.
Updated by Marius BĂLTEANU 10 months ago
- Related to Defect #40204: `rake redmine:plugins` fails with the error "Don't know how to build task 'redmine:plugins:assets'" added
Updated by Marius BĂLTEANU 10 months ago
- included favicon in assets pipeline and switched to
favicon_link_tag
(https://apidock.com/rails/ActionView/Helpers/AssetTagHelper/favicon_link_tag) - updated installation docs
- moved all public assets (javascript, stylesheets, images and themes) from
public
toapp/assets
I'm wondering if it's a good ideea to split our assets from the one owned by outside entities, such as jQuery, jQuery UI or Tribute and move all these to vendor/javascripts
and vendor/stylesheets
.
Updated by Mizuki ISHIKAWA 10 months ago
Marius BĂLTEANU wrote in #note-18:
I made the following changes:
- included favicon in assets pipeline and switched to
favicon_link_tag
(https://apidock.com/rails/ActionView/Helpers/AssetTagHelper/favicon_link_tag)- updated installation docs
- moved all public assets (javascript, stylesheets, images and themes) from
public
toapp/assets
I'm wondering if it's a good ideea to split our assets from the one owned by outside entities, such as jQuery, jQuery UI or Tribute and move all these to
vendor/javascripts
andvendor/stylesheets
.
I've been using a non-standard theme( e.g., https://github.com/farend/redmine_theme_farend_basic , https://github.com/farend/redmine_theme_farend_bleuclair ) with Redmine, and after the changes in r22696, I needed to do the following to keep the theme working:
1. Move the theme from public/themes to app/assets/themes.
2. Change the path where the theme imports Redmine's application.css. (Refer to the commit: https://github.com/farend/redmine_theme_farend_bleuclair/commit/c06330c064d19b02ea3bb6ca7e9a5c37d6c33519)
However, making the change in step 2 causes the theme to break in earlier versions of Redmine, so I'm looking for a way to make the change compatible with both versions.
Additionally, when I added the standard theme to app/assets/themes, it became a target for git staging. I would appreciate a change in .gitignore to prevent this.
diff --git a/.gitignore b/.gitignore
index f25b049a5..f38d49c39 100644
--- a/.gitignore
+++ b/.gitignore
@@ -27,10 +27,10 @@
/public/assets/*
/public/dispatch.*
/public/plugin_assets/*
-/public/themes/*
-!/public/themes/alternate
-!/public/themes/classic
-!/public/themes/README
+/app/assets/themes/*
+!/app/assets/themes/alternate
+!/app/assets/themes/classic
+!/app/assets/themes/README
/tmp/*
/tmp/cache/*
/tmp/pdf/*
Updated by Marius BĂLTEANU 10 months ago
Mizuki ISHIKAWA wrote in #note-19:
Marius BĂLTEANU wrote in #note-18:
[...]
I've been using a non-standard theme( e.g., https://github.com/farend/redmine_theme_farend_basic , https://github.com/farend/redmine_theme_farend_bleuclair ) with Redmine, and after the changes in r22696, I needed to do the following to keep the theme working:
1. Move the theme from public/themes to app/assets/themes.
2. Change the path where the theme imports Redmine's application.css. (Refer to the commit: https://github.com/farend/redmine_theme_farend_bleuclair/commit/c06330c064d19b02ea3bb6ca7e9a5c37d6c33519)
Yes, both changes are required. The first change could be avoided if we keep the themes folder in public/themes
, but I find very confusing to have the sources and the assets in the same public directory.
However, making the change in step 2 causes the theme to break in earlier versions of Redmine, so I'm looking for a way to make the change compatible with both versions.
Indeed, I don't see right now a way to keep them compatible, but I will investigate more in the following days.
Additionally, when I added the standard theme to app/assets/themes, it became a target for git staging. I would appreciate a change in .gitignore to prevent this.
[...]
I will update the ignore files for git, mercurial and svn, thanks!
Regarding the directory for non-standard themes, what do you think if we move them to themes
in the root directory as we have for plugins
? The structure will be the following:
app/assets/themes +- alternate/ +- classic/ themes/ +- <theme name>/ | +- favicon/ | +- <favicon file> (e.g. favicon.ico, favicon.png) | +- javascripts/ | +- theme.js | +- stylesheets/ +- application.css
In this way, when you install Redmine and you want to customize it, you work only with themes
and plugins
directories, you don't need to browse the internal structure from app.
Updated by Marius BĂLTEANU 10 months ago
- Related to Patch #40221: Update wiki content related to how to create a custom theme added
Updated by Mizuki ISHIKAWA 9 months ago
Marius BĂLTEANU wrote in #note-20:
Regarding the directory for non-standard themes, what do you think if we move them to
themes
in the root directory as we have forplugins
? The structure will be the following:
[...]In this way, when you install Redmine and you want to customize it, you work only with
themes
andplugins
directories, you don't need to browse the internal structure from app.
I agree. Having a similar structure to the plugins directory ensures consistency and should make it easier to understand for both new users and existing users.
Updated by Marius BĂLTEANU 9 months ago
- Category set to Code cleanup/refactoring
- Status changed from New to Resolved
- Resolution set to Fixed
Now that #40137 is finished, I think we can consider this feature done from developing point of view. I will keep this ticket as Resolved until we prepare a detailed changelog and a wiki page.
Please open new issue if you find any problem!
Updated by Marius BĂLTEANU 7 months ago
- Related to Patch #40559: Fix incorrect icon image paths for Wiki help pages added
Updated by Marius BĂLTEANU 7 months ago
- Status changed from Resolved to Closed
I think we can consider this feature done, please open new tickets in case of issues.
Thanks again to everyone who contributed to this change.
Updated by Go MAEDA 4 months ago
- Related to Patch #37748: Favicon takes a long time to load added
Updated by Marius BĂLTEANU about 2 months ago
- Status changed from Closed to Reopened
We should update Propshaft to latest version: https://github.com/rails/propshaft/releases/tag/v1.1.0
Updated by Go MAEDA about 1 month ago
- Related to Defect #29625: application.css imported by themes not covered by cache control versioning added
Updated by Marius BĂLTEANU 24 days ago
- File 0001-Updates-propshaft-gem-to-1.1.0-39111.patch 0001-Updates-propshaft-gem-to-1.1.0-39111.patch added
Takashi Kato, can you take a look on the attach patch that fixes the update to propshaft 1.1.0? I would like to include this update in the release.
Updated by Takashi Kato 23 days ago
- File 0001-Add-asset-path-to-default-to-support-old-style-theme.patch 0001-Add-asset-path-to-default-to-support-old-style-theme.patch added
- File 0002-Upgrade-propshaft-to-1.1.0.patch 0002-Upgrade-propshaft-to-1.1.0.patch added
Thank you for the patch for propshaft 1.1.0. Since Redmine::AssetLoadPath is a property of Rails.application.assets, there’s no need to create multiple instances. I’ve therefore modified a few lines accordingly.
Additionally, the Redmine::AssetPath module includes a mechanism to support asset pipelines for themes compatible with Redmine 5.1 and earlier versions. While some third-party themes have created a separate branch for Redmine 6 or later, this generally should not be necessary.
I’ve added a test to enable themes using older formats to reference the default application.css.
Updated by Mizuki ISHIKAWA 20 days ago
I found ThemesTest#test_old_theme_compatibility test fails. https://www.redmine.org/builds/logs/build_trunk_mysql_ruby-3.2_1247.html
Probably because the diff in the 0001-Add-asset-path-to-default-to-support-old-style-theme.patch test/fixtures/themes/foo_theme/stylesheets/application.css file was missing when it was committed in r23173.
Error: ThemesTest#test_old_theme_compatibility: Errno::ENOENT: No such file or directory @ dir_initialize - /var/lib/redmine/test/fixtures/themes/foo_theme lib/redmine/themes.rb:115:in `asset_paths' test/integration/lib/redmine/themes_test.rb:115:in `test_old_theme_compatibility'
Updated by Go MAEDA 19 days ago
Mizuki ISHIKAWA wrote in #note-31:
I found ThemesTest#test_old_theme_compatibility test fails. https://www.redmine.org/builds/logs/build_trunk_mysql_ruby-3.2_1247.html
Probably because the diff in the 0001-Add-asset-path-to-default-to-support-old-style-theme.patch test/fixtures/themes/foo_theme/stylesheets/application.css file was missing when it was committed in r23173.[...]
Fixed in r23175. Thank you.
Updated by Mizuki ISHIKAWA 19 days ago
The current code seems to be warned by rubocop. https://github.com/redmine/redmine/actions/runs/11639710239/job/32416198818
You can fix it with the following diff:
diff --git a/test/integration/lib/redmine/themes_test.rb b/test/integration/lib/redmine/themes_test.rb
index 7dc6b8df0..10cfac660 100644
--- a/test/integration/lib/redmine/themes_test.rb
+++ b/test/integration/lib/redmine/themes_test.rb
@@ -117,9 +117,9 @@ class ThemesTest < Redmine::IntegrationTest
Rails.application.assets.load_path.clear_cache
asset = Rails.application.assets.load_path.find('themes/foo_theme/application.css')
- get "/assets/#{asset.digested_path.to_s}"
+ get "/assets/#{asset.digested_path}"
assert_response :success
- assert_match %r{url\(\"/assets/application-\w+\.css\"\)}, response.body
+ assert_match %r{url\("/assets/application-\w+\.css"\)}, response.body
end
end
Updated by Mizuki ISHIKAWA 19 days ago
Mizuki ISHIKAWA wrote in #note-33:
The current code seems to be warned by rubocop. https://github.com/redmine/redmine/actions/runs/11639710239/job/32416198818
It was already corrected in r23176. Thank you very much.
Updated by Marius BĂLTEANU 18 days ago
- Status changed from Reopened to Closed
Thanks for working on these fixes!
Updated by Katsuya HIDAKA 16 days ago
Redmine does not start in production after r23174.
$ bin/rails s -e production => Booting Puma => Rails 7.2.2 application starting in production => Run `bin/rails server --help` for more startup options Exiting /redmine/config/initializers/10-patches.rb:125:in `initialize': undefined local variable or method `manifest_path' for an instance of Propshaft::Assembly (NameError) if Rails.application.config.assets.redmine_detect_update && (!manifest_path.exist? || manifest_outdated?) ^^^^^^^^^^^^^ Did you mean? manifest_outdated? from /bundle/ruby/3.3.0/gems/propshaft-1.1.0/lib/propshaft/railtie.rb:43:in `new' from /bundle/ruby/3.3.0/gems/propshaft-1.1.0/lib/propshaft/railtie.rb:43:in `block in <class:Railtie>' from /bundle/ruby/3.3.0/gems/activesupport-7.2.2/lib/active_support/lazy_load_hooks.rb:94:in `block in execute_hook'
This error appears to be caused by the following change in Propshaft v1.0.0.
https://github.com/rails/propshaft/pull/195
Updated by Go MAEDA 16 days ago
- Status changed from Closed to Reopened
I have confirmed the issue reported in #note-36.
Katsuya HIDAKA wrote in #note-36:
Redmine does not start in production after r23174.
[...]This error appears to be caused by the following change in Propshaft v1.0.0.
https://github.com/rails/propshaft/pull/195
Updated by Katsuya HIDAKA 16 days ago
- File Fixed-an-issue-where-Redmine-would-not-start-due-to-an-error-in-Propshaft.patch Fixed-an-issue-where-Redmine-would-not-start-due-to-an-error-in-Propshaft.patch added
I've attached a patch to fix the error in #note-36.
The default value of the config.manifest_path
is set to config.assets.output_path.join(".manifest.json")
(code), which is the same value returned by the manifest_path
method in Propshaft v0.8.0 (code).
I've tested that Redmine starts in production and displays a third-party theme (Bleuclair) correctly.
Updated by Marius BĂLTEANU 11 days ago
- Related to Defect #41712: Fix Path for Plugin Assets Added by Rake Task added
Updated by Marius BĂLTEANU 11 days ago
Takashi Kato, do you have any ideea why we load automatically the assets also from plugins/<plugin_name>/app/assets
?
Updated by Takashi Kato 11 days ago
- File 0001-Support-plugin-multiple-asset-path.patch 0001-Support-plugin-multiple-asset-path.patch added
Marius BĂLTEANU wrote in #note-41:
Takashi Kato, do you have any ideea why we load automatically the assets also from
plugins/<plugin_name>/app/assets
?
The attached patch supports plugins/<plugin_name>/assets
and plugins/<plugin_name>/app/assets
.
Updated by Marius BĂLTEANU 11 days ago
- Related to Defect #41726: Allow plugin assets to be loaded from app/assets added