오픈 소스 모험: 에피소드 19: Imba 1 앱을 Imba 2로 포팅

7031 단어 javascriptimba
내가 Imba 1에 빠져 있던 시절에 장난감 Imba 1 앱을 많이 썼습니다. Imba 2에서 다시 작성하기에 좋은 시기입니다.

포팅에는 몇 가지 어려움이 있습니다.
  • Imba 1을 Imba 2 코드로 자동 변환할 수 있는 방법이 없습니다. 이는 CoffeeScript의 다른 방언이며 단순한 구문이 아닙니다
  • .
  • 구성 요소 모델이 동일하지 않음, Imba 2는 웹 구성 요소를 기반으로 함
  • Imba 2는 웹 구성 요소를 기반으로 하기 때문에 전반적으로 의심스러운 결정입니다. 한 가지 큰 문제는 SVG와 작동하지 않는다는 것입니다. 저는 제 앱에서 많은 SVG를 사용했습니다. Imba가 할 수 있는 해결 방법이 있는지 모르겠습니다
  • .
  • 내 미니 앱은 모두 SCSS를 사용했고, Imba 2에는 대신 Tailwind와 유사한 자체 CSS 시스템이 있습니다
  • .

    Imba 1 eyes , Imba 2 eyes - which you can see in action here 전에 그런 포트를 하나 했습니다.

    그나저나 Imba 2 강제 탭make Imba 2 code look like total ass on github은 탭 들여쓰기에 8개의 공백을 사용하므로 OMG가 보기 흉합니다. By comparison 2-spaced Imba 1 code looks neat .

    탭을 2칸으로 표시하도록 편집기를 설정할 수 있지만 이 설정은 모든 곳에 적용되지 않습니다(예: GitHub 또는 블로그 게시물). 나는 그것이 절대적으로 끔찍한 선택이라고 생각하며 Imba는 다른 프런트 엔드 기술이 사용하는 표준 2 공간으로 전환해야 합니다.

    Imba 1 눈 코드




    tag Eye < svg:g
      prop mx
      prop my
    
      def render
        let max_eye_movement = 0.3 * data:sz
        let rx = data:x
        let ry = data:y
        if mx != null && my != null
          let dx = mx - data:x
          let dy = my - data:y
          let dl = Math.sqrt(dx*dx + dy*dy)
          if dl > max_eye_movement
            dx = max_eye_movement * dx/dl
            dy = max_eye_movement * dy/dl
          rx += dx
          ry += dy
        <self>
          <svg:circle.eye1 cx=(data:x) cy=(data:y) r=(data:sz)>
          <svg:circle.eye2 cx=(rx) cy=(ry) r=(data:sz * 0.5) css:fill=(data:color)>
          <svg:circle.eye3 cx=(rx) cy=(ry) r=(data:sz * 0.2)>
    
    tag App
      def mount
        schedule(raf: true)
    
      def onmousemove(event)
        let native_event = event:_event
        let svg = document.get-element-by-id("eyes")
        let rect = svg.get-bounding-client-rect()
        @mx = native_event:pageX - rect:x
        @my = native_event:pageY - rect:y
    
      def eye_distance(eye1, eye2)
        let dx = eye1:x - eye2:x
        let dy = eye1:y - eye2:y
        Math.sqrt((dx * dx) + (dy * dy))
    
      def can_place_eye(new_eye)
        @eyes.every do |eye|
          eye_distance(eye, new_eye) >= eye:sz + new_eye:sz + 5
    
      def random_color
        let h = Math.random() * 360
        let s = Math.round(50 + Math.random() * 50)
        let l = Math.round(30 + Math.random() * 40)
        "hsl({h}, {s}%, {l}%)"
    
      def setup
        let wh = window:inner-height
        let ww = window:inner-width
        @mx = Math.random() * ww
        @my = Math.random() * wh
        @eyes = []
        for i in [1..1000]
          let sz = 20 + Math.random() * 60
          let x = sz + Math.random() * (ww - 2 * sz)
          let y = sz + Math.random() * (wh - 2 * sz)
          let new_eye = {x: x, y: y, sz: sz, color: random_color}
          if can_place_eye(new_eye)
            @eyes.push(new_eye)
    
      def render
        <self>
          <svg:svg#eyes>
            for eye in @eyes
              <Eye[eye] mx=@mx my=@my>
    
    Imba.mount <App>
    


    여기서 주목할만한 디자인은 Eye 구성 요소가 svg:g에서 상속된다는 것입니다.

    임바 1 눈 scss




    @import 'normalize-scss';
    @include normalize();
    
    body {
      overflow: hidden;
    }
    
    .App {
      width: 100vw;
      height: 100vh;
      overflow: hidden;
    
      svg {
        width: 100vw;
        height: 100vh;
    
        display: block;
        background-color: #aaa;
    
        .eye1 {
          fill: white;
          stroke: black;
          stroke-width: 3px;
        }
        .eye2 {
          stroke: black;
          stroke-width: 1px;
        }
        .eye3 {
          fill: black;
        }
      }
    }
    


    쉽게 일반 CSS일 수 있지만 저는 일반 CSS가 마음에 들지 않습니다. 또한 패키지에서 정규화를 사용하면 관련 부분이 몇 줄에 불과합니다.

    Imba 2 눈 코드


    <svg>가 아닌 모든 눈을 자신의 눈<g>으로 만들어야 했습니다. 이 장난감 앱의 경우 괜찮지만 Imba 2의 접근 방식이 적합하지 않은 경우가 많습니다.

    # NOTE:
    # Can't inherit from svg:g yet in imba2
    # so this is a bit awkward
    
    tag spooky-eye
      def render
        let max_eye_movement = 0.3 * data.sz
        let rx = data.x
        let ry = data.y
    
        if mx != null && my != null
          let dx = mx - data.x
          let dy = my - data.y
          let dl = Math.sqrt(dx*dx + dy*dy)
          if dl > max_eye_movement
            dx = max_eye_movement * dx/dl
            dy = max_eye_movement * dy/dl
          rx += dx
          ry += dy
    
        <self>
          <svg>
            <svg:circle.eye1 cx=(data.x) cy=(data.y) r=(data.sz)>
            <svg:circle.eye2 cx=(rx) cy=(ry) r=(data.sz * 0.5) css:fill=(data.color)>
            <svg:circle.eye3 cx=(rx) cy=(ry) r=(data.sz * 0.2)>
    
    tag app-root
      def eye_distance(eye1, eye2)
        let dx = eye1.x - eye2.x
        let dy = eye1.y - eye2.y
        Math.sqrt((dx * dx) + (dy * dy))
    
      def can_place_eye(new_eye)
        eyes.every do |eye|
          eye_distance(eye, new_eye) >= eye.sz + new_eye.sz + 5
    
      def random_color()
        let h = Math.random() * 360
        let s = Math.round(50 + Math.random() * 50)
        let l = Math.round(30 + Math.random() * 40)
        "hsl({h}, {s}%, {l}%)"
    
      def onmousemove(event)
        let element = document.get-element-by-id("eyes")
        let rect = element.get-bounding-client-rect()
        mx = event.page-x - rect.x
        my = event.page-y - rect.y
    
      def constructor
        super
        let wh = window.inner-height
        let ww = window.inner-width
        mx = Math.random() * ww
        my = Math.random() * wh
        eyes = []
        for i in [1 .. 1000]
          let sz = 20 + Math.random() * 60
          let x = sz + Math.random() * (ww - 2 * sz)
          let y = sz + Math.random() * (wh - 2 * sz)
          let new_eye = {x: x, y: y, sz: sz, color: random_color()}
          if can_place_eye(new_eye)
            eyes.push(new_eye)
    
      def render
        <self#eyes :mousemove.onmousemove>
          for eye in eyes
            <spooky-eye data=eye mx=mx my=my>
    


    Imba 2 눈 scss



    Imba 2의 새로운 css 시스템에 포팅하지 않았습니다. 포팅을 할 당시에는 아직 거기에 없었기 때문에 내가 가지고 있던 SCSS를 재사용할 뿐입니다.

    @import 'normalize-scss';
    @include normalize();
    
    app-root {
      display: block;
      width: 100vw;
      height: 100vh;
      overflow: hidden;
      background-color: #aaa;
    
      svg {
        position: fixed;
        top: 0;
        left: 0;
        width: 100vw;
        height: 100vh;
        pointer-events: none;
    
        .eye1 {
          fill: white;
          stroke: black;
          stroke-width: 3px;
        }
        .eye2 {
          stroke: black;
          stroke-width: 1px;
        }
        .eye3 {
          fill: black;
        }
      }
    }
    


    다음에 온다



    다음 몇 편의 에피소드에서는 Imba 1 앱을 몇 개 더 Imba 2로 이식하고 새로운 CSS 시스템과 같은 새로운 Imba 2의 기능 중 일부를 사용해 볼 수 있습니다.

    좋은 웹페이지 즐겨찾기