lib/lookbook/engine.rb in lookbook-1.5.5 vs lib/lookbook/engine.rb in lookbook-2.0.0.beta.0

- old
+ new

@@ -1,141 +1,101 @@ -require "view_component" -require "action_cable/engine" -require "listen" require "yard" module Lookbook class Engine < Rails::Engine isolate_namespace Lookbook config.autoload_paths << File.expand_path(root.join("app/components")) - config.before_configuration do - config.lookbook = Lookbook.config - end - - initializer "lookbook.viewcomponent.config_sync" do - opts.preview_paths += config.view_component.preview_paths - opts.preview_controller ||= config.view_component.preview_controller - - if config.view_component.view_component_path.present? - opts.components_path = config.view_component.view_component_path - end - end - initializer "lookbook.assets.serve" do config.app_middleware.use( Rack::Static, - urls: ["/lookbook-assets"], root: root.join("public").to_s + urls: ["/lookbook-assets"], + root: root.join("public").to_s ) end - initializer "lookbook.file_watcher.paths" do - opts.listen_paths += opts.preview_paths - opts.listen_paths << opts.components_path - end + config.before_configuration do + config.lookbook = Lookbook.config - initializer "lookbook.file_watcher.previews" do - file_watcher.watch(opts.listen_paths, opts.listen_extensions, wait_for_delay: 0.5) do |changes| - parser.parse { run_hooks(:after_change, changes) } + if defined?(ViewComponent) + config.lookbook.using_view_component = true + else + require "view_component" + config.lookbook.using_view_component = false end end - initializer "lookbook.file_watcher.pages" do - file_watcher.watch(opts.page_paths, opts.page_extensions) do |changes| - Engine.pages.load(Engine.page_paths) - Engine.mark_changed - Engine.websocket.broadcast(:reload) - run_hooks(:after_change, changes) - end - end + config.after_initialize do + if opts.using_view_component || Rails.env.test? + vc_config = Engine.host_config.view_component - initializer "lookbook.parser.previews_load_callback" do - parser.after_parse do |code_objects| - Engine.previews.load(code_objects.all(:class)) - Engine.mark_changed - Engine.websocket.broadcast(:reload) - end - end + opts.preview_paths += vc_config.preview_paths + opts.preview_controller = vc_config.preview_controller + opts.preview_layout = vc_config.default_preview_layout - # The preview controller handles the rendering of individual previews. - # - # Lookbook injects some actions into whichever controller has been - # specified by the user in order to render previews within the context of - # the particular controller class instance so that any before_action/after_action - # callbacks will be correctly processed. - config.after_initialize do - @preview_controller = opts.preview_controller.constantize - @preview_controller.class_eval { include Lookbook::PreviewActions } - end + vc_config.show_previews = true - config.after_initialize do - if Rails.application.respond_to?(:server) - Rails.application.server { file_watcher.start if listen? } - elsif process.supports_listening? - file_watcher.start if listen? + if vc_config.view_component_path.present? + opts.component_paths << vc_config.view_component_path + end end + + opts.reload_on_change = host_config.reload_classes_only_on_change if opts.reload_on_change.nil? end config.after_initialize do - Engine.pages.load(Engine.page_paths) - parser.parse { run_hooks(:after_initialize) } + reloaders.add(:previews, Engine.preview_watch_paths, opts.listen_extensions, &Engine.method(:load_previews)) + reloaders.add(:pages, Engine.page_watch_paths, opts.page_extensions, &Engine.method(:load_pages)) + reloaders.execute + + Engine.run_hooks(:after_initialize) end def opts Lookbook.config end - def run_hooks(event_name, *args) - Engine.hooks.for_event(event_name).each do |hook| - hook.call(Lookbook, *args) - end - end - def parser @_parser ||= PreviewParser.new(opts.preview_paths, Engine.tags) end - def file_watcher - @_file_watcher ||= FileWatcher.new(force_polling: opts.listen_use_polling) + def reloaders + @_reloaders ||= Reloaders.new end - def process - @_process ||= Process.new(env: Rails.env) - end - - def listen? - opts.listen && process.supports_listening? - end - class << self + delegate :app_name, to: :runtime_context + def mount_path routes.find_script_name({}) end def mounted? mount_path.present? end - def app_name - name = if Rails.application.class.respond_to?(:module_parent_name) - Rails.application.class.module_parent_name - else - Rails.application.class.parent_name - end - name.underscore + def reloading? + opts.reload_on_change end + def auto_refresh? + reloading? && runtime_context.web? && FileWatcher.evented? + end + def websocket - if mounted? - use_websocket = opts.auto_refresh && opts.listen && process.supports_listening? - @websocket ||= use_websocket ? Websocket.new(mount_path, logger: Lookbook.logger) : Websocket.noop - else - Websocket.noop - end + @_websocket ||= auto_refresh? ? Websocket.new(mount_path, logger: Lookbook.logger) : NullWebsocket.new end + def runtime_context + @_runtime_context ||= RuntimeContext.new(env: Rails.env) + end + + def theme + @_theme ||= Lookbook::Theme.new(opts.ui_theme, opts.ui_theme_overrides) + end + def panels @_panels ||= PanelStore.init_from_config end def inputs @@ -148,42 +108,94 @@ def hooks @_hooks ||= HookStore.init_from_config end + def run_hooks(event_name, *args) + hooks.for_event(event_name).each do |hook| + hook.call(Lookbook, *args) + end + end + + def host_app_path + Rails.application.root.join("app") + end + + def host_config + Rails.application.config + end + + def view_paths + ActionView::ViewPaths.all_view_paths.flat_map do |view_path| + view_path.paths.map { |path| Pathname(path.to_s) } + end + end + def component_paths - @_component_paths ||= Array(PathUtils.to_absolute(opts.components_path)) + @_component_paths ||= begin + paths = [*opts.component_paths, *Engine.view_paths, host_app_path] + PathUtils.normalize_paths(paths) + end end def page_paths @_page_paths ||= PathUtils.normalize_paths(opts.page_paths) end + alias_method :page_watch_paths, :page_paths + def preview_paths @_preview_paths ||= PathUtils.normalize_paths(opts.preview_paths) end + def preview_watch_paths + return @_preview_watch_paths if @_preview_watch_paths + + paths = [*opts.preview_paths, opts.components_path, *opts.listen_paths, *view_paths].uniq + @_preview_watch_paths ||= PathUtils.normalize_paths(paths) + end + def pages @_pages ||= PageCollection.new end def previews @_previews ||= PreviewCollection.new end - def mark_changed - @_last_changed = nil + def preview_controller + return @_preview_controller if @_preview_controller + + @_preview_controller = opts.preview_controller.constantize + @_preview_controller.include PreviewControllerActions end - def last_changed - @_last_changed ||= (Time.now.to_f * 1000).to_i + def load_previews(changes = nil) + changed_files = [*changes[:added], *changes[:modified]] if changes + parser.parse(changed_files) do |code_objects| + previews.load(code_objects.all(:class), changes) + end end - attr_reader :preview_controller + def load_pages(changes = nil) + pages.load(Engine.page_paths, changes) + end + + def notify_clients(changes = nil) + return unless changes.present? + + websocket.broadcast(:reload) + run_hooks(:after_change, changes.to_h) + end + + def files_changed(modified, added, removed) + changes = {modified: modified, added: added, removed: removed} + reloaders.register_changes(changes) + notify_clients(changes) + end end at_exit do - file_watcher.stop - run_hooks(:before_exit) + Engine.run_hooks(:before_exit) end end end