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