스웨덴 최대 부동산 포털인 Hemnet에서 ReasonML 테스트

10712 단어 hemnetreasonreact
매주Hemnet 고유 방문자 수는 280만 명이며, 이는 인구가 약 천만 명인 국가에서 상당히 많은 수입니다.

1년에 두 번 우리는 새로운 기술을 테스트하거나 새로운 개발에 대해 읽을 수 있는 역량 개발의 날을 갖습니다. 저는 메인 앱에 ReasonML을 통합하기로 했습니다.

Reason에 대해 들어본 적이 없다면 새로운 설명서 웹 사이트가 좋습니다https://reasonml.org/.

실험



이 앱은 현재 Ruby on Rails 및 React(JavaScript)의 대규모 코드베이스입니다. 따라서 형식 안전성을 시험해 볼 수 있는 완벽한 장소입니다.

예를 들어 일반적인 사용 사례가 포함된 구성 요소를 변환하기로 선택했습니다. 다른 구성 요소/이미지 가져오기, 추적 이벤트 보내기 및 React 컨텍스트 사용.

암호



다음은 코드에 대해 동료로부터 받은 몇 가지 질문에 대한 답변입니다.

수입 명세서 없음



모든 모듈, 모든.re 파일은 Reason의 모듈이며 전역적으로 액세스할 수 있습니다. 이것은 문제처럼 보일 수 있지만 에서는 완벽하게 괜찮습니다.

React.string("텍스트")



React는 여러 유형을 유효한 자식(숫자, 문자열, 요소 또는 배열)으로 허용하지만 Reason은 정적으로 유형이 지정되기 때문에 모든 것이 일관된 유형으로 매핑되어야 합니다. 따라서 React.string 를 사용하여 이 문자열이 React.element 에 매핑될 것임을 컴파일러에 알립니다. React.int , React.floatReact.array 의 경우 각각에 대한 함수가 있습니다.

패턴 매칭 및 옵션 유형



Reason에는 nullundefined가 존재하지 않습니다. JavaScript와 상호 운용성을 수행할 때 아마도 undefined prop은 Some(value) 또는 None 인 Reason의 option type 에 매핑됩니다.

{switch (price) {
 | Some(price) =>
   <span className="mb-2">
     <PriceBox price originalPrice />
   </span>
 | None => React.null
}}


이유는 좋은 방법으로 모든 가능한 상태를 처리하도록 강제하고 스위치의 경우가 동일한 유형을 반환해야 하므로 React.nullprice일 때 None를 반환합니다. JavaScript에서 우리는

{price && (
  <span className="signup-toplisting-promo__price">
    <PriceBox price={price} originalPrice={originalPrice} />
  </span>
)}


소품



다음 예제에서는 소품에 값이 없는 것처럼 보일 수 있습니다. 이것은 punning 때문입니다. 이는 변수가 소품과 동일한 이름을 가질 때 즉, price={price}price 가 되는 약칭입니다.

let price = 50;
let originalPrice = 100;

<PriceBox price originalPrice />


JavaScript 코드에 바인딩



구성 요소 라이브러리의 Heading를 사용하고 있었으므로 바인딩이 필요했습니다. as 은 Reason에는 예약된 키워드이지만 JavaScript에는 없습니다. underscore in front을 추가하여 Reason에서 사용할 수 있으며 컴파일러는 컴파일된 코드에서 제거합니다. 이것을 name mangling이라고 합니다.

/* Hemnet.re */

module Heading = {
  [@bs.module "@hemnet/react"] [@react.component]
  external make:
    (~_as: string, ~styleType: string, ~children: React.element) =>
    React.element =
    "Heading";
};

/* Usage */
<Hemnet.Heading _as="h2" styleType="h3">
  {React.string("Raketen")}
</Hemnet.Heading>


추적 이벤트를 Google 애널리틱스로 전송하기 위해 레이블이 지정된 인수를 사용하는 실제 매개변수가 무엇인지 명확하게 해주는 모듈을 만들었습니다. 더 이상 매개변수의 순서를 기억할 필요가 없습니다.

/* GoogleAnalytics.re */
/* Binds to the global variable `ga` */
[@bs.val] external ga: (string, string) => unit = "ga";

let track = (~category, ~action) => ga(category, action);

/* Usage */
GoogleAnalytics.track(
  ~category="event-category",
  ~action="event-action",
)


참고: 바인딩은 훨씬 더 안전한 형식으로 만들 수 있습니다. 예를 들어 variants을 사용하여 특정 값만 JavaScript 코드로 보낼 수 있습니다.

테스트



테스트는 여전히 Jest와 동일한 설정을 사용하고 컴파일된 코드를 대상으로 할 수 있으므로 동일하게 유지됩니다.

측정항목


bsb -clean-world를 실행하여 컴파일된 모든 코드를 제거한 다음 bsb -make-world를 실행하는 클린 빌드는 약 200ms 내에 이유 코드를 컴파일합니다.



컴파일러가 감시 모드에서 실행 중이면 파일 변경 사항을 훨씬 더 빠르게 컴파일합니다.



이것은 몇 가지 모듈에만 적용되지만 더 큰 프로젝트에서 Reason을 사용했을 때 클린 빌드에서 본 가장 긴 컴파일 시간은 ~8-10초입니다. 파일을 변경할 때 일반적으로 400ms 미만입니다.

최종 결과



유일한 시각적 차이는 링크 색상인데, 이는 Tailwind(실험에서도 테스트함)와 글로벌 스타일 간의 충돌로 인한 것입니다. 시각적 요소 외에도 훌륭한 유형 추론 덕분에 구성 요소를 사용하는 것이 훨씬 안전합니다.


이유 실험
생산



좋은 웹페이지 즐겨찾기