Hacktoberfest 2026: những issue maintainer đã đánh dấu cho tháng Mười, đang mở và phù hợp người mới. Xem issue Hacktoberfest

Dumping exceptions in live editor

Đang mở
#26 0 bình luận 0 reaction 0 người được giao Xem trên GitHub

Chưa có ai nhận issue này.

Đánh giá

Độ khó
5/5
Thời gian dự kiến
Hơn một tuần
Mức phù hợp với người mới
25/100
Loại issue
Tái cấu trúc
Độ rõ ràng
Cần làm rõ
Mức độ hoạt động
Đình trệ
Công nghệ
javascript, ruby
Lĩnh vực
frontend, web-dev

Hướng nghiên cứu

Bắt đầu bằng cách lần theo các phương thức vòng đời trong đoạn mã React::NativeLibrary và Hyperloop::Component::Mixin đã dán, đặc biệt là các đường dẫn callback được bọc trong rescue Exception. Tái hiện sự cố sập live editor khi thêm before_mount hoặc một phương thức vòng đời khác, sau đó xác minh rằng exception bên dưới được xử lý mà không cần các bản vá rescue tạm thời của #barrie và trang vẫn có thể sử dụng được.

Do mô hình lập chỉ mục viết ra từ nội dung của issue.

Mô tả

bug

The live editor can crash the whole page if the user adds one of the lifecycle methods (before_mount, etc). The only fix so far is the patch below which catches and dumps an exception. Each change has comment #barrie

We need to find a better solution and this needs to be removed before the rename.

module React
find_and_render_component
  class NativeLibrary
    class << self
      def imports(native_name)
        @native_prefix = "#{native_name}."
        self
      end

      def rename(rename_list)
        # rename_list is a hash in the form: native_name => ruby_name, native_name => ruby_name
        rename_list.each do |js_name, ruby_name|
          native_name = lookup_native_name(js_name)
          if lookup_native_name(js_name)
            create_component_wrapper(self, native_name, ruby_name) ||
              create_library_wrapper(self, native_name, ruby_name)
          else
            raise "class #{name} < React::NativeLibrary could not import #{js_name}. "\
            "Native value #{scope_native_name(js_name)} is undefined."
          end
        end
      end

      def import_const_from_native(klass, const_name, create_library)
        begin
          native_name = lookup_native_name(const_name) ||
                        lookup_native_name(const_name[0].downcase + const_name[1..-1])
          native_name && (
            create_component_wrapper(klass, native_name, const_name) || (
              create_library &&
                create_library_wrapper(klass, native_name, const_name)))
        rescue Exception
          # barrie
        end
      end

      def const_missing(const_name)
        import_const_from_native(self, const_name, true) || super
      end

      def method_missing(method, *args, &block)
        component_class = const_get(method) if const_defined?(method, false)
        component_class ||= import_const_from_native(self, method, false)
        raise 'could not import a react component named: '\
              "#{scope_native_name method}" unless component_class
        React::RenderingContext.render(component_class, *args, &block)
      end

      private

      def lookup_native_name(js_name)
        native_name = scope_native_name(js_name)
        `eval(#{native_name}) !== undefined && native_name`
      # rubocop:disable Lint/RescueException  # that is what eval raises in Opal >= 0.10.
      rescue Exception
        nil
        # rubocop:enable Lint/RescueException
      end

      def scope_native_name(js_name)
        "#{@native_prefix}#{js_name}"
      end

      def create_component_wrapper(klass, native_name, ruby_name)
        if React::API.native_react_component?(native_name)
          new_klass = klass.const_set ruby_name, Class.new
          new_klass.class_eval do
            include Hyperloop::Component::Mixin
            imports native_name
          end
          new_klass
        end
      end

      def create_library_wrapper(klass, native_name, ruby_name)
        klass.const_set ruby_name, Class.new(React::NativeLibrary).imports(native_name)
      end
    end
  end
end

module Hyperloop
  class Component
    class << self
      def mounted_components
        @mounted_components ||= Set.new
      end

      def force_update!
        components = mounted_components.to_a
        components.each do |comp|
          next unless mounted_components.include? comp
          comp.force_update!
        end
      end
    end

    module Mixin
      def self.included(base)
        base.include(Hyperloop::Store::Mixin)
        base.include(React::Component::API)
        base.include(React::Callbacks)
        base.include(React::Component::Tags)
        base.include(React::Component::DslInstanceMethods)
        base.include(React::Component::ShouldComponentUpdate)
        base.class_eval do
          class_attribute :initial_state
          define_callback :before_mount
          define_callback :after_mount
          define_callback :before_receive_props
          define_callback :before_update
          define_callback :after_update
          define_callback :before_unmount
          define_callback(:after_error) { React::API.add_after_error_hook(base) }
        end
        base.extend(React::Component::ClassMethods)
      end

      def self.deprecation_warning(message)
        React::Component.deprecation_warning(name, message)
      end

      def deprecation_warning(message)
        React::Component.deprecation_warning(self.class.name, message)
      end

      def initialize(native_element)
        @native = native_element
        init_store
      end

      def emit(event_name, *args)
        if React::Event::BUILT_IN_EVENTS.include?(built_in_event_name = "on#{event_name.to_s.event_camelize}")
          params[built_in_event_name].call(*args)
        else
          params["on_#{event_name}"].call(*args)
        end
      end

      def component_will_mount
        begin
          React::IsomorphicHelpers.load_context(true) if React::IsomorphicHelpers.on_opal_client?
          React::State.set_state_context_to(self) do
            Hyperloop::Component.mounted_components << self
            run_callback(:before_mount)
          end
        rescue Exception
          # barrie
        end
      end

      def component_did_mount
        begin
          React::State.set_state_context_to(self) do
            run_callback(:after_mount)
            React::State.update_states_to_observe
          end
        rescue Exception
          # barrie
        end
      end

      def component_will_receive_props(next_props)
        # need to rethink how this works in opal-react, or if its actually that useful within the react.rb environment
        # for now we are just using it to clear processed_params
        begin
          React::State.set_state_context_to(self) { run_callback(:before_receive_props, next_props) }
          @_receiving_props = true
        rescue Exception
          # barrie
        end
      end

      def component_will_update(next_props, next_state)
        begin
          React::State.set_state_context_to(self) { run_callback(:before_update, next_props, next_state) }
          params._reset_all_others_cache if @_receiving_props
          @_receiving_props = false
        rescue Exception
          # barrie
        end
      end

      def component_did_update(prev_props, prev_state)
        begin
          React::State.set_state_context_to(self) do
            run_callback(:after_update, prev_props, prev_state)
            React::State.update_states_to_observe
          end
        rescue Exception
          # barrie
        end
      end

      def component_will_unmount
        begin
          React::State.set_state_context_to(self) do
            run_callback(:before_unmount)
            React::State.remove
            Hyperloop::Component.mounted_components.delete self
          end
        rescue Exception
          # barrie
        end
      end

      def component_did_catch(error, info)
        React::State.set_state_context_to(self) do
          run_callback(:after_error, error, info)
        end
      end

      attr_reader :waiting_on_resources

      def update_react_js_state(object, name, value)
        if object
          name = "#{object.class}.#{name}" unless object == self
          # Date.now() has only millisecond precision, if several notifications of
          # observer happen within a millisecond, updates may get lost.
          # to mitigate this the Math.random() appends some random number
          # this way notifactions will happen as expected by the rest of hyperloop
          set_state(
            '***_state_updated_at-***' => `Date.now() + Math.random()`,
            name => value
          )
        else
          set_state name => value
        end
      end

      def set_state_synchronously?
        @native.JS[:__opalInstanceSyncSetState]
      end

      def render
        raise 'no render defined'
      end unless method_defined?(:render)

      def _render_wrapper
        React::State.set_state_context_to(self, true) do
          element = React::RenderingContext.render(nil) { render || '' }
          @waiting_on_resources =
            element.waiting_on_resources if element.respond_to? :waiting_on_resources
          element
        end
      end

      def watch(value, &on_change)
        Observable.new(value, on_change)
      end

      def define_state(*args, &block)
        React::State.initialize_states(self, self.class.define_state(*args, &block))
      end
    end
  end
end
Ngôn ngữ chính
CSS
Star
5
Fork
11
Chỉ số merge pull request
Không có pull request nào được merge trong 30 ngày

Hướng dẫn đóng góp

Mở hướng dẫn đóng góp

Bắt đầu từ đâu

  1. Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
  2. Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
  3. Fork repository và làm thay đổi trên một nhánh.
  4. Mở pull request có tham chiếu số hiệu của issue.

Issue khác của hyperstack-org/website

Tất cả issue của hyperstack-org/website

Issue tương tự

Thêm issue về Web Dev

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.