분류 Reactjs

Remix.run 처음 살펴보기

컨텐츠 정보

  • 조회 347 (작성일 )

본문

오늘 Remix Run Supporter Preview가 마침내 출시되었습니다. Remix는 새로운 React 프레임 워크입니다.


https://dev.to/dabit3/a-first-look-at-remix-run-449a


Remix에 대해 가장 흥분되는 점 중 하나는 그 뒤에 있는 팀입니다.

Michael JacksonRyan Florence는 React 커뮤니티에서 가장 지식이 풍부한 엔지니어 중 일부이며 개인적으로, AWS에서 고객과 상담 할 때, 일할 때 내 경력에서 수없이 사용했던 많은 것 (React Router, UNPKGReach UI와 같은)을 구축했습니다. 


저를 흥분 시키는 또 다른 점은 React가 처음 출시 된 이후 지난 몇 년 동안 일어난 혁신과 Remix에서 이러한 아이디어를 어떻게 구축했는지 입니다.


이 빠른 게시물에서는 Remix의 작동 방식을 보여 드리겠습니다.


  1. 새 프로젝트 만들기
  2. 자격 증명 설정
  3. 라우팅 구성
  4. 동적 라우팅 추가
  5. 동적 데이터 가져 오기
  6. 경로 매개 변수를 사용한 동적 데이터 가져 오기
  7. 글로벌 리믹스 구성 사용

여기에서 Remix 작동 방식에 대한 비디오 연습을 확인할 수도 있습니다.


리믹스 정보 


가격 


리믹스는 무료가 아닙니다. Remix를 사용하려면 인디 (연간 $ 250) 또는 엔터프라이즈 (연간 $ 1,000) 라이선스를 구매해야 합니다. 이것에 대한 많은 의견이 있습니다. 나는 양쪽 모두에 좋은 주장이 있다고 생각한다. 그래서 여기 내 것이 있습니다.


컨설팅을 시작할 때 1 시간의 교육에 대해 개인적으로 $250 이상을 지불 했으므로 팀에서 1 년 동안 지원하는 동안 앱을 쉽게 구축 할 수 있는 프레임 워크를 신뢰할 수 있습니다. 그만한 가치가 있다고 생각합니다. 그것. 무료 인 Next.js와 같은 프레임 워크를 살펴보고 그만한 가치가 없다고 결정할 수도 있습니다. 두 의견 모두 전적으로 유효한 IMO입니다.


하루가 끝나면 고품질 앱을 빌드하고 품질 저하 없이 가능한 한 빠르고 효율적으로 이를 수행 할 수 있기를 원합니다. 시간이 돈이기 때문에 종종 저를 더 좋고 더 빠르게 만들 수 있는 도구에 투자합니다. 내 기존 스킬 셋을 활용할 수 있습니다.)


SSR 


Remix의 전체 아이디어는 모든 것이 SSR이라는 것입니다. 또한 Next.js와 같은 것보다 훨씬 낮은 수준의 API를 가지고 있어 전체 Request 객체를 노출하고 페이지를 렌더링 하기 전에 헤더와 같은 것을 수정할 수 있습니다. 나는 여전히 모든 기능을 알지 못하지만 언뜻 보기에 Next.js의 금속 / 더 구성 가능한 버전에 더 가깝지만 SSG가 없는 것으로 보며 솔직히 알지 못했던 중첩 경로에 대한 몇 가지 이점이 있습니다. 아직 탐험했지만 흥미로워 요.


Routing 


Remix와 다른 프레임 워크 (예 : Next.js)의 또 다른 큰 차이점은 라우팅 작동 방식입니다. 중첩 된 경로와 매개 변수는 Remix에서 지원되며 "Remix에서 이해해야 할 중요한 아이디어입니다"(문서에 따르면).


React Router Dom의 Outlet을 사용하면 사용하기 매우 간단한 API로 중첩 된 경로의 계층을 구축 할 수 있습니다.


import React from "react";
import { Link, Outlet } from "react-router-dom";
import { useRouteData } from "@remix-run/react";

export default function Team() {
  let data = useRouteData();
  return (
    <div>
      <h2>Team</h2>
      <ul>
        {data.map((member) => (
          <li key={member.id}>
            <Link to={member.login}>{member.login}</Link>
          </li>
        ))}
      </ul>
      <hr />
      <Outlet />
    </div>
  );
}


링크를 사용하여 탐색 할 때 Outlet은 탐색 된 경로에서 새 콘텐츠를 렌더링 합니다.


HTTP Caching 


Remix에는 경로에 대한 데이터를 반환 할 뿐만 아니라 캐시 제어 헤더 전송을 포함한 전체 응답을 보낼 수 있는 로더 개념이 있습니다. 로더 및 경로에 대한 헤더를 설정하는 간단한 API를 사용하면 캐시 기능에 내장 된 브라우저 (및 CDN)를 쉽게 활용할 수 있습니다.


예를 들어 응답에 캐시 헤더를 설정하면 사용자가 동일한 경로를 방문하면 데이터를 가져 오지 않고 캐시를 사용합니다. 그리고 서버 앞에 CDN을 넣으면 CDN이 캐시에 저장하기 때문에 서버는 실제로 요청을 거의 처리하지 않습니다.


Code 


충분히 설명 했으니 코드를 살펴 보겠습니다.


프로젝트 생성 


Remix 라이선스 구독을 구매하면 대시 보드에 액세스 할 수 있습니다. 이 대시 보드에서 라이선스 세부 정보, 설명서 및 결제 정보를 볼 수 있습니다.

Remix Dashboard 


이것은 단순히 오픈 소스인 내가 사용한 대부분의 프레임 워크와는 훨씬 다른 경험이지만, 이것은 모두 페이 월 뒤에 숨겨져 있습니다.


이 대시 보드에는 빠른 시작 자습서를 포함하여 필요한 모든 것이 있습니다.


시작하려면 Express를 서버로 사용하는 오픈 소스 스타터 프로젝트를 복제하는 것이 좋습니다.


$ git clone git@github.com:remix-run/starter-express.git my-remix-app


기본적으로 단일 명령을 사용하여 배포 할 수 있도록 Firebase를 지원합니다.


firebase deploy


앞으로 그들은 다음과 같은 다양한 클라우드 서비스 공급자에 대한 배포도 지원할 계획입니다.


  • Firebase
  • Vercel
  • AWS Amplify
  • Architect
  • Azure
  • Netlify

액세스 제한 


유료 고객에게만 액세스를 제한하는 방법이 궁금 할 수 있습니다. 이렇게 하는 방법은 앱을 실행하는 데 필요한 최신 노드 모듈을 설치하려면 비밀 키를 포함하도록 다음과 같은 .npmrc 파일을 구성해야 한다는 것입니다.

//npm.remix.run/:_authToken=your-unique-token

# This line tells npm where to find @remix-run packages.
@remix-run:registry=https://npm.remix.run



이것이 구성되면 npm 또는 yarn을 사용하여 종속성을 설치할 수 있습니다.


프로젝트 구조 


다음은 Remix 관련 프로젝트 구성을 살펴 봅니다.


remix-app  
└───app
│   │   App.tsx
│   │   entry-browser.tsx
│   │   entry-server.tsx
│   │   global.css
│   │   tsconfig.json
│   └───routes
│       │   index.js
│       │   404.js
│       │   500.js
│       │   index.css
└───config
│   │   shared-tsconfig.json
└───loaders
│    │   global.ts
│    │   tsconfig.json
│
└───public
│    │   favicon.ico
│    
└───.npmrc
│
└───remix.config.js
│
└───server.js


진입 점은 App.tsx이며 다음과 같습니다.


import React from "react";
import { Meta, Scripts, Styles, Routes, useGlobalData } from "@remix-run/react";

export default function App() {
  let data = useGlobalData();

  return (
    <html lang="en">
      <head>
        <meta charSet="utf-8" />
        <Meta />
        <Styles />
      </head>
      <body>
        <Routes />
        <Scripts />
        <footer>
          <p>This page was rendered at {data.date.toLocaleString()}</p>
        </footer>
      </body>
    </html>
  );
}


흥미로운 점은 다음과 같습니다.


let data = useGlobalData();


loaders / global.ts에서 전역 값, 변수 (정적 및 동적 모두) 또는 기본 레이아웃을 렌더링 하기 위해 서버에서 로드 해야 하는 모든 것을 구성 할 수 있습니다. 예를 들어 여기에서 앱 버전을 정의하고 앱 전체에서 사용하고 싶다고 가정 해 보겠습니다. 여기에서 정의 할 수 있습니다.


import type { DataLoader } from "@remix-run/core";

let loader: DataLoader = async () => {
  return {
    date: new Date(),
    version: "V2.0"
  };
};

export = loader;


그리고 다음과 같이 사용하십시오.


let data = useGlobalData();
const version = data.version;


Routing 


문서에서 : 리믹스의 경로는 일반적으로 "app / routes"폴더 내부 또는 remix.config.routes를 사용하여 수동으로 두 가지 방법으로 정의 할 수 있습니다.


따라서 route / contact.js라는 파일을 만들면 http : // myapp / contact에서 사용할 수 있습니다.


하지만 언급 했듯이 remix.config.js에서 정의 할 수도 있습니다. remix.config.js의 코드 주석에서 :


A hook for defining custom routes based on your own file
conventions. This is not required, but may be useful if
you have custom/advanced routing requirements.


다음은 상용구에서 제공하는 예입니다.


routes(defineRoutes) {
  return defineRoutes(route => {
    route(
      // The URL path for this route.
      "/pages/one",
      // The path to this route's component file, relative to `appDirectory`.
      "pages/one.tsx",
      // Options:
      {
        // The path to this route's data loader, relative to `loadersDirectory`.
        loader: "...",
        // The path to this route's styles file, relative to `appDirectory`.
        styles: "..."
      }
    );
  });
},


이 과정에서 Remix의 의견을 무시하고 싶거나 우회해야 하는 경우 사용자 지정 경로 구성을 정의 할 수 있습니다.


데이터 로딩 


Remix의 가장 흥미롭고 강력한 기능 중 하나는 데이터를 로드하는 방법입니다.


이 접근 방식은 경로와 로더를 결합하여 동적 데이터 가져 오기를 활성화합니다.


문서에서 : Remix의 페이지 데이터는 "route data loaders"라는 파일에서 가져옵니다. 이러한 로더는 서버 측에서만 실행되므로 데이터베이스에 대한 직접 연결을 포함하여 데이터를 로드 하는 데 필요한 모든 노드 모듈을 사용할 수 있습니다.


로더의 이름을 경로와 동일하게 지정하면 Remix가 렌더링 전에 자동으로 호출하고 해당 데이터를 경로에서 사용할 수 있도록 합니다


이것이 어떻게 작동하는지 살펴 보겠습니다.


다음과 같은 route / people.ts에 경로와 페이지를 생성한다고 가정 해 보겠습니다.


// routes/people.ts
import React, { useState, useEffect } from "react";

export default function People() {
  return (
    <div>
      <h2>Star Wars Characters</h2>
      // todo, fetch & map over star wars characters from API
    </div>
  );
}


이 경로가 렌더링 될 때 사람들의 배열에 대한 데이터를 가져 와서 구성 요소에서 사용할 수 있도록 만들고 싶습니다.


이를 위해 다음 코드를 사용하여 people.ts라는 loaders / routes 디렉토리에 새 파일을 만들 수 있습니다.


// loaders/routes/people.ts
module.exports = () => {
  return fetch(`https://swapi.dev/api/people/`);
};


이제 Remix의 useRouteData API를 사용하여 경로에서 이 데이터에 액세스 할 수 있습니다.


// routes/people.ts
import React, { useState, useEffect } from "react";
import { Link } from "react-router-dom";
import { useRouteData } from "@remix-run/react";

export default function People() {
  const data = useRouteData()
  return (
    <div>
      <h2>Star Wars Characters</h2>
      {
        data.results.map((result, index) => (
          <div key={index}>
            <Link to={`/person/${index + 1}`}>
              <h1>{result.name}</h1>            
            </Link>
          </div>
        ))
      }
    </div>
  );
}


큰 질문 


가져 오기를 기다린 다음 res.json을 기다릴 필요가없는 이유는 무엇입니까? Remix는 로더를 기다리고 있고, fetch는 응답으로 해결되고 Remix는 정확히 그 유형의 객체를 기대하기 때문입니다.


문서에서 : 마지막 부분에서 머리를 긁적 일 수 있습니다. 왜 우리는 일반적인 await res.json()으로 fetch 응답을 풀지 않아도 됩니까?


한동안 Node.js 세계를 둘러 보셨다면 "요청"과 "응답"의 다양한 버전이 있다는 것을 알게 될 것입니다. Express API req, res는 아마도 가장 유비쿼터스이지만 어디를 가든지 항상 약간 다릅니다.


브라우저는 Fetch API를 제공 할 때 window.fetch에 대한 사양을 생성 할 뿐만 아니라 가져 오기가 보내고 반환하는 항목, 요청, 헤더 및 응답에 대한 사양도 생성했습니다. MDN에서 이러한 API에 대해 읽을 수 있습니다.


자체 API를 만드는 대신 Web Fetch API 위에 Remix를 빌드 했습니다.


캐싱 추가 


이 게시물의 시작 부분에서 언급 한 캐싱 메커니즘을 구현하는 방법을 살펴 보겠습니다.


다음과 같이 업데이트 할 수 있습니다.


const { json } = require("@remix-run/loader");
let res = await fetch(swapi);
let data = await res.json();
return json(data, { headers: { "cache-control": "max-age=3600"}})


다음 시간 동안 브라우저는 해당 리소스를 다시 요청하지 않으며 다음 방문자에 대해 CDN도 요청하지 않습니다.


동적 경로, 경로 매개 변수 및 데이터 가져 오기 결합 


이것은 동적 경로에서 어떻게 작동합니까? 예를 들어 / person / # person-id와 같은 경로로 드릴 다운하고 데이터를 가져 오려면 어떻게 해야 합니까?


작동 방식은 다음과 같습니다. 두 개의 새 파일이 필요합니다. 하나는 경로 용이고 다른 하나는 로더 용입니다.


먼저 loaders / person / $ id.js에 다음과 같은 로더를 만듭니다.


// loaders/person/$id.js
module.exports = ({ params }) => {
  return fetch(`https://swapi.dev/api/people/${params.id}`)
};


다음으로 route / person / $ id.js와 같은 경로를 생성합니다. Remix는 URL (person / $ id의 $ id 부분)에서 매개 변수를 구문 분석하여 로더에 전달합니다.


// routes/person/$id.js
import React from "react";
import { useRouteData } from "@remix-run/react";

export default function Person() {
  const user = useRouteData()
  return (
    <div>
      <h2>{user.name}</h2>
      <h3>Homeworld - { user.homeworld }</h3>
      <p>Height - {user.height}</p>
    </div>
  );
}


API에서 가져온 데이터는 이제 useRouteData를 사용하여 사용할 수 있습니다.


Remix.run 비디오로 시작 및 실행 


결론 


전반적으로 저는 Remix를 사용하는 것을 정말 즐기고 있습니다. 수년 동안 현대 및 레거시 웹 기술에서 보아온 발전을 기반으로 하는 하이브리드 React 웹 애플리케이션을 구축하는 완전히 새로운 접근 방식입니다.


나는 Remix가 시간이 지남에 따라 계속 나아질 것으로 기대하지만 OSS가 아니라는 점을 고려할 때 얼마나 멀리 또는 빨리 나올지 확신 할 수 없습니다.


새로운 지불 모델을 시도한 Ryan과 Michael에게 박수를 보내고 어떻게 될지 기대됩니다. OSS로 수익을 창출하는 문제는 아직 완전히 해결되지 않았기 때문에 이를 위한 새로운 접근 방식은 현재와 미래에 오픈 소스 작업을 수익성 있고 유지 관리 할 수 ​​있도록 하려는 모든 사람을 위한 기반을 마련합니다.


또한 Remix와 Next.js의 차이점에 대해 좀 더 자세히 설명하는 내 게시물을 확인하십시오.