diff options
Diffstat (limited to 'lib/gitlab/webpack/manifest.rb')
-rw-r--r-- | lib/gitlab/webpack/manifest.rb | 102 |
1 files changed, 98 insertions, 4 deletions
diff --git a/lib/gitlab/webpack/manifest.rb b/lib/gitlab/webpack/manifest.rb index d2c01bbd55e..6a8a7e24ebd 100644 --- a/lib/gitlab/webpack/manifest.rb +++ b/lib/gitlab/webpack/manifest.rb @@ -1,16 +1,33 @@ # frozen_string_literal: true -require 'webpack/rails/manifest' +require 'net/http' +require 'uri' module Gitlab module Webpack - class Manifest < ::Webpack::Rails::Manifest - # Raised if a supplied asset does not exist in the webpack manifest + class Manifest + # Raised if we can't read our webpack manifest for whatever reason + class ManifestLoadError < StandardError + def initialize(message, orig) + super "#{message} (original error #{orig})" + end + end + + # Raised if webpack couldn't build one of your entry points + class WebpackError < StandardError + def initialize(errors) + super "Error in webpack compile, details follow below:\n#{errors.join("\n\n")}" + end + end + + # Raised if a supplied entry point does not exist in the webpack manifest AssetMissingError = Class.new(StandardError) class << self + include Gitlab::Utils::StrongMemoize + def entrypoint_paths(source) - raise ::Webpack::Rails::Manifest::WebpackError, manifest["errors"] unless manifest_bundled? + raise WebpackError, manifest["errors"] unless manifest_bundled? dll_assets = manifest.fetch("dllAssets", []) entrypoint = manifest["entrypoints"][source] @@ -21,9 +38,86 @@ module Gitlab "/#{::Rails.configuration.webpack.public_path}/#{p}" end else + raise AssetMissingError, "Can't find asset '#{source}' in webpack manifest" + end + end + + def asset_paths(source) + raise WebpackError, manifest["errors"] unless manifest_bundled? + + paths = manifest["assetsByChunkName"][source] + if paths + # Can be either a string or an array of strings. + # Do not include source maps as they are not javascript + [paths].flatten.reject { |p| p =~ /.*\.map$/ }.map do |p| + "/#{::Rails.configuration.webpack.public_path}/#{p}" + end + else raise AssetMissingError, "Can't find entry point '#{source}' in webpack manifest" end end + + def clear_manifest! + clear_memoization(:manifest) + end + + private + + def manifest_bundled? + !manifest["errors"].any? { |error| error.include? "Module build failed" } + end + + def manifest + if ::Rails.configuration.webpack.dev_server.enabled + # Don't cache if we're in dev server mode, manifest may change ... + load_manifest + else + # ... otherwise cache at class level, as JSON loading/parsing can be expensive + strong_memoize(:manifest) { load_manifest } + end + end + + def load_manifest + data = if ::Rails.configuration.webpack.dev_server.enabled + load_dev_server_manifest + else + load_static_manifest + end + + Gitlab::Json.parse(data) + end + + def load_dev_server_manifest + host = ::Rails.configuration.webpack.dev_server.manifest_host + port = ::Rails.configuration.webpack.dev_server.manifest_port + uri = Addressable::URI.new(scheme: 'http', host: host, port: port, path: dev_server_path) + + # localhost could be blocked via Gitlab::HTTP + response = HTTParty.get(uri.to_s, verify: false) # rubocop:disable Gitlab/HTTParty + + return response.body if response.code == 200 + + raise "HTTP error #{response.code}" + rescue => e + raise ManifestLoadError.new("Could not load manifest from webpack-dev-server at #{uri} - is it running, and is stats-webpack-plugin loaded?", e) + end + + def load_static_manifest + File.read(static_manifest_path) + rescue => e + raise ManifestLoadError.new("Could not load compiled manifest from #{static_manifest_path} - have you run `rake webpack:compile`?", e) + end + + def static_manifest_path + ::Rails.root.join( + ::Rails.configuration.webpack.output_dir, + ::Rails.configuration.webpack.manifest_filename + ) + end + + def dev_server_path + "/#{::Rails.configuration.webpack.public_path}/#{::Rails.configuration.webpack.manifest_filename}" + end end end end |