Skip to content

Commit

Permalink
Fixes #37102 - webpack 5
Browse files Browse the repository at this point in the history
  • Loading branch information
MariaAga authored and ekohl committed Jan 26, 2024
1 parent 066dd49 commit 89c6104
Show file tree
Hide file tree
Showing 43 changed files with 505 additions and 490 deletions.
1 change: 0 additions & 1 deletion Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ gem 'sprockets-rails', '~> 3.0'
gem 'responders', '~> 3.0'
gem 'roadie-rails', '~> 3.0'
gem 'deacon', '~> 1.0'
gem 'webpack-rails', '~> 0.9.8'
gem 'mail', '~> 2.7'
gem 'sshkey', '~> 2.0'
gem 'dynflow', '>= 1.6.5', '< 2.0.0'
Expand Down
6 changes: 4 additions & 2 deletions Procfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# Run Rails & Webpack concurrently
# If you wish to use a different server then the default, use e.g. `export RAILS_STARTUP='puma -w 3 -p 3000 --preload'`
rails: [ -n "$RAILS_STARTUP" ] && env PRY_WARNING=1 $RAILS_STARTUP || [ -n "$BIND" ] && bin/rails server -b $BIND || env PRY_WARNING=1 bin/rails server
# you can use WEBPACK_OPTS to customize webpack server, e.g. 'WEBPACK_OPTS='--https --key /path/to/key --cert /path/to/cert.pem --cacert /path/to/cacert.pem' foreman start '
webpack: [ -n "$NODE_ENV" ] && ./node_modules/.bin/webpack-dev-server-without-h2 --config config/webpack.config.js $WEBPACK_OPTS || env NODE_ENV=development ./node_modules/.bin/webpack-dev-server-without-h2 --config config/webpack.config.js $WEBPACK_OPTS

# you can use WEBPACK_OPTS to customize webpack server, e.g. 'WEBPACK_OPTS=--progress' foreman start '
# filter out webpack options that are commonly used but not supported by webpack 5 and not needed in the new configutation as webpack is not run as a server anymore
webpack: FILTERED_WEBPACK_OPTS=$(echo $WEBPACK_OPTS | sed -e 's/--key [^ ]*//g' -e 's/--public [^ ]*//g' -e 's/--https [^ ]*//g' -e 's/--cert [^ ]*//g' -e 's/--cacert [^ ]*//g') && [ -n "$NODE_ENV" ] && npx webpack --config config/webpack.config.js --watch $FILTERED_WEBPACK_OPTS || env NODE_ENV=development npx webpack --config config/webpack.config.js --watch $FILTERED_WEBPACK_OPTS
1 change: 1 addition & 0 deletions app/assets/config/manifest.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
//= link late_load.js
//= link_tree ../../../vendor/assets/fonts
//= link_tree ../images
//= link application.css
Expand Down
16 changes: 14 additions & 2 deletions app/assets/javascripts/application.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,22 @@
//= require lookup_keys

$(function() {
$(document).trigger('ContentLoad');
if(window.allJsLoaded){
$(document).trigger('ContentLoad');
}
else {
$(document).on('loadJS', function() {
$(document).trigger('ContentLoad');
});}
});


// Override jQuery's ready function to run only after all scripts are loaded instead of when the DOM is ready
$.fn.ready = function(fn) {
this.on('loadJS', fn);
return this;
};

// Prevents all links with the disabled attribute set to "disabled"
// from being clicked.
var handleDisabledClick = function(event, element){
Expand All @@ -21,7 +34,6 @@ var handleDisabledClick = function(event, element){
$(document).on('click', 'a[disabled="disabled"]', function(event) {
return handleDisabledClick(event, this);
});

function onContentLoad() {
if ($('input[focus_on_load=true]').length > 0) {
$('input[focus_on_load]')
Expand Down
53 changes: 53 additions & 0 deletions app/assets/javascripts/late_load.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
function load_dynamic_javascripts(html) {
function waitForAllLoaded() {
// Wait for all plugins js modules to be loaded before loading the javascript content
return new Promise(function(resolve) {
// window.allPluginsLoaded is set to {} when plugins are starting to load
// if there are no plugins window.allPluginsLoaded is never defined
if (window.allPluginsLoaded === undefined || Object.values(window.allPluginsLoaded).every(Boolean)) {
resolve();
} else {
function handleLoad() {
if (window.allPluginsLoaded === undefined || Object.values(window.allPluginsLoaded).every(Boolean)) {
resolve();
// Remove the event listener
document.removeEventListener('loadPlugin', handleLoad);
}
}
document.addEventListener('loadPlugin', handleLoad);
}
});
}
waitForAllLoaded().then(async function() {
// parse html string
var template = document.createElement('template');
template.innerHTML = html;
var doc = new DOMParser().parseFromString(html, 'text/html');
var copyChildren = [...doc.head.children];
const loadScript = async scripts => {
if (scripts.length === 0) {
// All scripts are loaded
window.allJsLoaded = true;
const loadJS = new Event('loadJS');
document.dispatchEvent(loadJS);
return;
}
const script = scripts.shift();
if (script.src) {
// if script is just a link, add it to the head
const scriptTag = document.createElement('script');
scriptTag.src = script.src;
scriptTag.onload = function() {
// To load the next script only after the current one is loaded
loadScript(scripts);
};
document.head.appendChild(scriptTag);
} else {
// if the script is a script tag, evaluate it and load the next one
await eval(script.innerHTML);
loadScript(scripts);
}
};
loadScript(copyChildren);
});
}
16 changes: 0 additions & 16 deletions app/controllers/application_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ class ApplicationController < ActionController::Base
before_action :set_taxonomy, :require_mail, :check_empty_taxonomy
before_action :authorize
before_action :welcome, :find_selected_columns, :only => :index, :unless => :api_request?
prepend_before_action :allow_webpack, if: -> { Rails.configuration.webpack.dev_server.enabled }
around_action :set_timezone

attr_reader :original_search_parameter
Expand Down Expand Up @@ -399,21 +398,6 @@ def parameter_filter_context
Foreman::ParameterFilter::Context.new(:ui, controller_name, params[:action])
end

def allow_webpack
webpack_csp = {
script_src: [webpack_server], connect_src: [webpack_server],
style_src: [webpack_server], img_src: [webpack_server],
font_src: ["data: #{webpack_server}"], default_src: [webpack_server]
}

append_content_security_policy_directives(webpack_csp)
end

def webpack_server
port = Rails.configuration.webpack.dev_server.port
@dev_server ||= "#{request.protocol}#{request.host}:#{port}"
end

class << self
def parameter_filter_context
Foreman::ParameterFilter::Context.new(:ui, controller_name, nil)
Expand Down
5 changes: 0 additions & 5 deletions app/helpers/application_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -348,11 +348,6 @@ def hosts_count(resource_name = controller.resource_name)
@hosts_count ||= HostCounter.new(resource_name)
end

def webpack_dev_server
return unless Rails.configuration.webpack.dev_server.enabled
javascript_include_tag "#{@dev_server}/webpack-dev-server.js"
end

def accessible_resource_records(resource, order = :name)
klass = resource.to_s.classify.constantize
klass = klass.with_taxonomy_scope_override(@location, @organization) if klass.include? Taxonomix
Expand Down
23 changes: 23 additions & 0 deletions app/helpers/layout_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,29 @@ def javascript(*args)
content_for(:javascripts) { javascript_include_tag(*args) }
end

def javascript_include_tag(*params, **kwargs)
# Workaround for overriding javascript load with webpack_asset_paths, should be removed when webpack_asset_paths is removed
if kwargs[:source] == "webpack_asset_paths"
kwargs[:webpacked]
else
super(*params, **kwargs)
end
end

# @deprecated Previously provided by webpack-rails
def webpack_asset_paths(plugin_name, extension: 'js')
if extension == 'js'
Foreman::Deprecation.deprecation_warning('3.12', '`webpack_asset_paths` is deprecated, use `content_for(:javascripts) { webpacked_plugins_js_for(plugin_name) }` instead.')
[{
source: 'webpack_asset_paths',
webpacked: webpacked_plugins_js_for(plugin_name.to_sym),
}]
elsif extension == 'css'
Foreman::Deprecation.deprecation_warning('3.12', '`webpack_asset_paths` is deprecated and not needed for css assets.')
nil
end
end

# The target should have class="collapse [out|in]" out means collapsed on load and in means expanded.
# Target must also have a unique id.
def collapsing_header(title, target, collapsed = '')
Expand Down
47 changes: 28 additions & 19 deletions app/helpers/reactjs_helper.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
require 'webpack-rails'
require 'json'

module ReactjsHelper
# Mount react component in views
# Params:
Expand All @@ -11,10 +12,6 @@ def react_component(name, props = {})
content_tag('foreman-react-component', '', :name => name, :data => { props: props })
end

def webpacked_plugins_with_global_css
global_css_tags(global_plugins_list).join.html_safe
end

def webpacked_plugins_js_for(*plugin_names)
js_tags_for(select_requested_plugins(plugin_names)).join.html_safe
end
Expand All @@ -24,7 +21,26 @@ def webpacked_plugins_with_global_js
end

def webpacked_plugins_css_for(*plugin_names)
css_tags_for(select_requested_plugins(plugin_names)).join.html_safe
Foreman::Deprecation.deprecation_warning('3.12', '`webpacked_plugins_css_for` is deprecated, plugin css is already loaded.')
nil
end

def read_webpack_manifest
JSON.parse(Rails.root.join('public/webpack/manifest.json').read)
end

def get_webpack_foreman_vendor_js
Rails.cache.fetch('webpack_foreman_vendor_js', expires_in: 1.minute) do
data = read_webpack_manifest
foreman_vendor_js = data['assetsByChunkName']['foreman-vendor'].find { |value| value.end_with?('.js') }
javascript_include_tag("/webpack/#{foreman_vendor_js}")
end
end

def get_webpack_foreman_vendor_css
data = read_webpack_manifest
foreman_vendor_css = data['assetsByChunkName']['foreman-vendor'].find { |value| value.end_with?('.css') }
stylesheet_link_tag("/webpack/#{foreman_vendor_css}")
end

def select_requested_plugins(plugin_names)
Expand All @@ -39,30 +55,23 @@ def select_requested_plugins(plugin_names)

def js_tags_for(requested_plugins)
requested_plugins.map do |plugin|
javascript_include_tag(*webpack_asset_paths(plugin.to_s, :extension => 'js'))
name = plugin.to_s.tr('-', '_')
javascript_tag("window.tfm.tools.loadPluginModule('/webpack/#{name}','#{name}','./index');".html_safe)
end
end

def global_js_tags(requested_plugins)
requested_plugins.map do |plugin|
plugin[:files].map do |file|
javascript_include_tag(*webpack_asset_paths("#{plugin[:id]}:#{file}", :extension => 'js'))
end
end
end

def global_css_tags(requested_plugins)
requested_plugins.map do |plugin|
plugin[:files].map do |file|
stylesheet_link_tag(*webpack_asset_paths("#{plugin[:id]}:#{file}", :extension => 'css'))
name = plugin[:id].to_s.tr('-', '_')
javascript_tag("window.tfm.tools.loadPluginModule('/webpack/#{name}','#{name}','./#{file}_index');".html_safe)
end
end
end

def css_tags_for(requested_plugins)
requested_plugins.map do |plugin|
stylesheet_link_tag(*webpack_asset_paths(plugin.to_s, :extension => 'css'))
end
Foreman::Deprecation.deprecation_warning('3.12', '`css_tags_for` is deprecated, No need to load CSS separately, since it should be referenced from the corresponding JS file.')
[]
end

def locale_js_tags
Expand Down
2 changes: 0 additions & 2 deletions app/services/foreman/env_settings_loader.rb
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,6 @@ def settings_map
'FOREMAN_REQUIRE_SSL' => [:boolean, :require_ssl],
'FOREMAN_SUPPORT_JSONP' => [:boolean, :support_jsonp],
'FOREMAN_MARK_TRANSLATED' => [:boolean, :mark_translated],
'FOREMAN_WEBPACK_DEV_SERVER' => [:boolean, :webpack_dev_server],
'FOREMAN_WEBPACK_DEV_SERVER_HTTPS' => [:boolean, :webpack_dev_server_https],
'FOREMAN_ASSETS_DEBUG' => [:boolean, :assets_debug],
'FOREMAN_HSTS_ENABLED' => [:boolean, :hsts_enabled],
'FOREMAN_DOMAIN' => [:string, :domain],
Expand Down
18 changes: 10 additions & 8 deletions app/views/layouts/base.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,8 @@
<%= favicon_link_tag "favicon.ico"%>
<%= stylesheet_link_tag *webpack_asset_paths('foreman-vendor', :extension => 'css') %>
<%= stylesheet_link_tag *webpack_asset_paths('bundle', :extension => 'css') %>
<%= get_webpack_foreman_vendor_css %>
<%= stylesheet_link_tag 'application' %>
<%= webpacked_plugins_with_global_css %>
<%= yield(:stylesheets) %>
<%= csrf_meta_tags %>
Expand All @@ -38,13 +36,17 @@
</head>

<body class='<%= body_css_classes %>'>
<%= javascript_include_tag *webpack_asset_paths('foreman-vendor', :extension => 'js') %>
<%= javascript_include_tag *webpack_asset_paths('vendor', :extension => 'js') %>
<%= javascript_include_tag *webpack_asset_paths('bundle', :extension => 'js') %>
<%= get_webpack_foreman_vendor_js %>
<%= javascript_include_tag('/webpack/vendor.js') %>
<%= javascript_include_tag('/webpack/bundle.js') %>
<%= javascript_include_tag 'application' %>
<%= webpacked_plugins_with_global_js %>
<%= webpack_dev_server %>
<%= yield(:javascripts) %>
<%= javascript_include_tag('late_load') %>
<script type="text/javascript">
const html = "<%= escape_javascript(yield(:javascripts)) %>"
load_dynamic_javascripts(html);
</script>
<script type="text/javascript">
<%= yield(:inline_javascripts) %>
</script>
Expand Down
4 changes: 0 additions & 4 deletions config/environments/development.rb
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,6 @@
end
end

# Allow disabling the webpack dev server from the settings
config.webpack.dev_server.enabled = SETTINGS.fetch(:webpack_dev_server, true)
config.webpack.dev_server.https = SETTINGS.fetch(:webpack_dev_server_https, false)

config.hosts += SETTINGS[:hosts]
config.hosts << SETTINGS[:fqdn]
# Backporting from Rails 7.0
Expand Down
2 changes: 0 additions & 2 deletions config/environments/production.rb
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,6 @@
# Do not dump schema after migrations.
config.active_record.dump_schema_after_migration = false

config.webpack.dev_server.enabled = false

# Log denied attributes into logger
config.action_controller.action_on_unpermitted_parameters = :log

Expand Down
2 changes: 0 additions & 2 deletions config/environments/test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,6 @@
# Randomize the order test cases are executed.
config.active_support.test_order = :random

config.webpack.dev_server.enabled = false

# Whitelist all plugin engines by default from raising errors on deprecation warnings for
# compatibility, allow them to override it by adding an ASDT configuration file.
config.after_initialize do
Expand Down
40 changes: 0 additions & 40 deletions config/initializers/assets.rb
Original file line number Diff line number Diff line change
@@ -1,13 +1,3 @@
module Webpack
module Rails
class Manifest
class << self
attr_writer :manifest
end
end
end
end

# Be sure to restart your server when you modify this file.
Foreman::Application.configure do |app|
# Version of your assets, change this if you want to expire all your assets.
Expand Down Expand Up @@ -53,35 +43,5 @@ class << self
ActionView::Base.assets_manifest = app.assets_manifest
end
end

# When the dev server is enabled, this static manifest file is ignored and
# always retrieved from the dev server.
#
# Otherwise we need to combine all the chunks from the various webpack
# manifests. This is the main foreman manifest and all plugins that may
# have one. We then store this in the webpack-rails manifest using our
# monkey patched function.
unless config.webpack.dev_server.enabled
if (webpack_manifest_file = Dir.glob("#{Rails.root}/public/webpack/manifest.json").first)
webpack_manifest = JSON.parse(File.read(webpack_manifest_file))

Foreman::Plugin.with_webpack.each do |plugin|
manifest_path = plugin.webpack_manifest_path
next unless manifest_path

Rails.logger.debug { "Loading #{plugin.id} webpack asset manifest from #{manifest_path}" }
assets = JSON.parse(File.read(manifest_path))

plugin_id = plugin.id.to_s
assets['assetsByChunkName'].each do |chunk, filename|
if chunk == plugin_id || chunk.start_with?("#{plugin_id}:")
webpack_manifest['assetsByChunkName'][chunk] = filename
end
end
end

Webpack::Rails::Manifest.manifest = webpack_manifest
end
end
end
end
Loading

0 comments on commit 89c6104

Please sign in to comment.