Gatsby 또는 React에서 파일을 원래 문자열로 가져오기

솔선수범하다


fully working CodeSandbox is here.이 글의 뒤에 당신은 자신의 블로그 글이나 사이트를 위해 어떻게 이런 구성 요소를 구축하는지 점차적으로 이해할 것입니다!

왜 나는 파일을 원시 문자열로 가져와야 합니까?


일부 독자들은 아마도 my blog's snippets page을 훑어보았을 것이다. 그곳에서 나는 가능한 한 깨끗한 형식으로 나의 모든 블로그 게시물의 관건적인 부분을 수집했다.이는 주로 the snippets page on Josh Comeau's blog의 영감을 받은 것이다.
나는 코드 세션 페이지에 내 재능을 추가했다. 나는 C#, Python, Node 등 언어의 코드 세션을 포함한 모든 곳에서 온 코드 세션을 가지고 있다.js
나는 내가 구축한 TypeScript/JavaScript 전환 프로그램이 매우 멋있다고 생각한다!이 글의 뒤에 우리는 자신의 언어 전환 프로그램을 어떻게 실현하는지 배울 것이다.
만약에 the repo for my blog을 보면 저는 폴더가 하나 있습니다. 모든 코드 세션은 실제적으로 하나의 일반적인 코드 파일로 자신의 언어를 사용합니다(.py은python, .cs은C#, .ts은TypeScript 등).본고의 말미에서 보듯이, 나는 실제적으로 이 파일들을 원시 문자열로 가져온 다음에 prism-react-renderer 라이브러리로 그것들을 문법적으로 강조했다.

내가 처음 시도한 연습


연습으로 우리는 단지 하나의 부분만 나타난다고 가정한다. 이것은 React 갈고리이고, 단지 일반적인ol'TypeScript 파일 (.ts 확장자), useDidMount.ts일 뿐이다.갈고리 자체의 실제 코드는 다음과 같다.
import { useState, useEffect } from 'react'

export const useDidMount = (): boolean => {
  const [didMount, setDidMount] = useState<boolean>(false)

  useEffect(() => {
    setDidMount(true)
  }, [])

  return didMount
}
내 블로그에 이 파일을 보여주기 위해 나는 먼저 천진스럽게 이 파일을 직접 가져와 toString()에 전화를 걸었다.😂 이 예제 어셈블리를 살펴보면 다음 작업을 수행할 수 있습니다.
import * as React from "react"
import { useDidMount } from '../snippets/useDidMount';

const ExampleComponent = () => {
    return (
        <>
            <p>useDidMount()</p>
            <pre>{useDidMount.toString()}</pre>
        </>
    )
}

export default ExampleComponent
만약 브라우저에서 이 구성 요소를 보았다면, 이 구성 요소의 결과는 다음과 같습니다.

그래...코드 세션의 원본 코드가 변환되어 모든 Webpack-y가 되었습니다. 사이트를 방문하고 깨끗한 코드 세션을 원하는 개발자에게는 이 점이 유용하지 않습니다.
그래서 우리는 표준 import 방법으로 코드 세션을 가져와서 렌더링할 수 없다는 것이 분명하다.
우리는 그것들을 원시 문자열로 가져올 필요가 있다.

솔루션


이 해결 방안은 내가 상상한 것보다 더 찾기 어렵다.Gatsby에 파일에 삽입할 수 있는 코드 세션이 gatsby-remark-embed-snippet이라는 패키지가 있습니다. 그러나 이것은markdown(또는 MDX) 파일에만 사용되는 비고 플러그인입니다. 어쨌든 본문을 작성할 때 이 패키지의 의존 항목은Gatsby V3와 호환되도록 업그레이드되지 않았습니다. 제 블로그는Gatsby V3를 사용하고 있습니다.나의 코드 세션 페이지는 .md 또는 .mdx 파일이 아니다.이것은 typescript react 구성 요소로 .tsx 파일에 위치하고 있으며 전체 페이지를 .md 또는 .mdx으로 재구성하고 싶지 않습니다.
그래서 일부 검색을 통해 저는 먼저 this Stackoverflow post about importing a CSS file in a raw fashion을 찾았습니다. 왜냐하면 최초의 포스터가 WYSIWYG 편집기를 만들고 편집기에서 작성한 방식에 따라 CSS를 보여주고 싶었기 때문입니다.그 게시물에서 나는 답을 찾았다.
파일을 원래 문자열로 가져오려면 require을 Webpack의 raw-loader과 함께 사용해야 합니다.
다음은 useDidMount의 예입니다.
const useDidMount = require("!!raw-loader!./useDidMount");
그리고 우리는 useDidMount.default.toString()을 사용하여 이 변수를 나타낼 수 있다. 예를 들어 <pre> 표지에서 다음과 같다.
<p>useDidMount()</p>
<pre>{useDidMount.default.toString()}</pre>
이렇게 하면 브라우저에서 코드 세그먼트의 소스 코드가 소스 파일에 표시되는 것과 동일하게 표시됩니다.

완벽해!이것이 바로 우리가 원하는 것이다!이제 실제 코드 문자열을 돋보이게 하는 문법 문제만 강조하면 시작할 수 있습니다!
나는 a Stack Overflow question for this, which I answered myself을 창립했지만, 어떤 이유로 그것은 부결되었다.😞 나는 왜 그런지 모르겠다. 만약 파일을 원시 문자열로 게이츠비 프로젝트의 비할인 파일이나 MDX 파일에 가져오려고 한다면, 나의 해결 방안은 유일하게 효과적이라고 생각한다.

재미있는 부분: 코드 세션 페이지에서 색다른 TypeScript / 자바Script 전환 프로그램을 어떻게 만들었는지!


따라서 이 글에서 배운 지식에 근거하여 저는 현재 snippets page에 이러한 코드 세션 전환 프로그램을 구축하는 방법을 소개하는 강좌를 제공할 것입니다.
코드 세션 전환기 구성 요소를 위한 이름은... 입니다.SnippetToggler ! 본질적으로, 우리는 코드 세션이라고 부르고 싶은 두 개의 파일 탭 (하나는javascript에, 하나는TypeScript에 사용) 을 설명하고, 그 다음에 실제 두 개의 코드 원본을 설명해야 한다. 이것은 전체 raw-loader 문제의 두통에서 비롯될 것이다.
그러면 구성 요소의 프레임워크부터 시작하여 필요한 도구에 대한 인터페이스 계약을 맺겠습니다.
export interface ISnippetTogglerProps {
    snippetLabel: string
    fileLabels: Array<string>
    typeScriptCode: string
    javaScriptCode: string
}

export function SnippetToggler(props: ISnippetTogglerProps) {
  return <></>
}
지금까지 줄곧 괜찮았다.우리가 해야 할 첫 번째 일은 모든 도구를 꺼내는 것이다.
export interface ISnippetTogglerProps {
    snippetLabel: string
    fileLabels: Array<string>
    typeScriptCode: string
    javaScriptCode: string
}

export function SnippetToggler(props: ISnippetTogglerProps) {
   const {
     snippetLabel,
     fileLabels,
     typeScriptCode,
     javaScriptCode
   } = props

  return <></>
}
그럼 우리가 필요로 하는 상태를 생각해 봅시다.우리는 이 두 부분 중 어느 부분을 실제적으로 보여야 하는지 알 수 있도록 boolean 상태 변수가 필요하다.나는 그것을 showJavaScript이라고 부른다.그런 다음 activeModeTextclassName을 사용하여 코드 세그먼트를 전환할 때 스타일과 레이블을 변경할 수 있습니다.
export interface ISnippetTogglerProps {
    snippetLabel: string
    fileLabels: Array<string>
    typeScriptCode: string
    javaScriptCode: string
}

export function SnippetToggler(props: ISnippetTogglerProps) {
  const {
    snippetLabel,
    fileLabels,
    typeScriptCode,
    javaScriptCode
  } = props

   const [showJavaScript, setShowJavaScript] = useState<boolean>(false)
   const activeModeText = showJavaScript ? "JavaScript" : "TypeScript"
   const className = activeModeText.toLowerCase()

  return <></>
}
그리고 렌더링 표시를 고려하기 시작합시다.코드 블록의 TypeScript 버전과 JavaScript 버전을 각각 const 변수 2개로 저장합니다.
export interface ISnippetTogglerProps {
    snippetLabel: string
    fileLabels: Array<string>
    typeScriptCode: string
    javaScriptCode: string
}

export function SnippetToggler(props: ISnippetTogglerProps) {
  const {
    snippetLabel,
    fileLabels,
    typeScriptCode,
    javaScriptCode
  } = props

  const [showJavaScript, setShowJavaScript] = useState<boolean>(false)
  const activeModeText = showJavaScript ? "JavaScript" : "TypeScript"
  const className = activeModeText.toLowerCase()

   const typeScriptBlock = (
     <>
         <code className={className}>{fileLabels[0]}</code>
         <Pre
             codeString={typeScriptCode}
             language="typescript"
         />
     </>
   )

   const javaScriptBlock = (
     <>
         <code className={className}>{fileLabels[1]}</code>
         <Pre
             codeString={javaScriptCode}
             language="javascript"
         />
     </>
   )

  return <></>
}
그중 <Pre/>조는 또 다른 반응조분이다(이것은 상당히 복잡하다. 표기된 문법 하이라이트 디스플레이가 아니라 자바스크립트 기반의 문법 하이라이트 디스플레이가 필요하기 때문이다. 여기서 나는 나의 <Pre/> 구성 요소의 각 부분을 생략했다. 예를 들어 복사 단추와 클릭할 때 오색 종이 부스러기를 표시한다. 나는 문법 하이라이트 디스플레이 테마를 github으로 고정시켰지만 선택할 수 있는 다른 주제도 많다. my <Pre/> component on the repository to explore the full one을 참조하시오.)
import React from "react";
import Highlight, { defaultProps, Language } from "prism-react-renderer";
import github from "prism-react-renderer/themes/github";

export interface IPreProps {
  codeString: string;
  language: Language;
}

export const Pre = (props: IPreProps) => {
  const { codeString, language } = props;

  return (
    <Highlight
      {...defaultProps}
      code={codeString}
      language={language}
      theme={github}
    >
      {({ className, style, tokens, getLineProps, getTokenProps }) => (
        <pre
          className={className}
          style={{
            ...style,
            padding: "2rem",
            position: "relative",
            overflowX: "scroll"
          }}
        >
          {tokens.map((line, i) => (
            <div {...getLineProps({ line, key: i })} style={style}>
              {line.map((token, key) => (
                <span {...getTokenProps({ token, key })} />
              ))}
            </div>
          ))}
        </pre>
      )}
    </Highlight>
  );
};
우리의 <SnippetToggler/> 구성 요소로 돌아가면 우리는 return 문구를 얻어 실제 스위치 구성 요소를 추가하고 상태 변수 showJavaScript을 사용하여 어떤 const 변수를 나타낼지 확정할 수 있다.
SnippetToggler 구성 요소의 최종 버전은 다음과 같습니다.
import * as React from "react";
import { useState } from "react";
import { Pre } from "./Pre";

export interface ISnippetTogglerProps {
  snippetLabel: string;
  fileLabels: Array<string>;
  typeScriptCode: string;
  javaScriptCode: string;
}

export function SnippetToggler(props: ISnippetTogglerProps) {
  const { snippetLabel, fileLabels, typeScriptCode, javaScriptCode } = props;

  const [showJavaScript, setShowJavaScript] = useState<boolean>(false);
  const activeModeText = showJavaScript ? "JavaScript" : "TypeScript";
  const className = activeModeText.toLowerCase();

  const typeScriptBlock = (
    <>
      <code className={className}>{fileLabels[0]}</code>
      <Pre codeString={typeScriptCode} language="typescript" />
    </>
  );

  const javaScriptBlock = (
    <>
      <code className={className}>{fileLabels[1]}</code>
      <Pre codeString={javaScriptCode} language="javascript" />
    </>
  );

   return (
     <>
       <h3 className={className}>{snippetLabel}</h3>
       <div>
         <label className={`switch ${className}`}>
           <input
             type="checkbox"
             onChange={() => setShowJavaScript(!showJavaScript)}
             checked={showJavaScript}
           />
           <span className="slider round" />
           <span className="switch-text snippet">
             {activeModeText} Mode Active
           </span>
         </label>
       </div>
       {showJavaScript ? javaScriptBlock : typeScriptBlock}
     </>
   );
}
좋아, 우리 끝났어!🎉
다음은 제가 <SnippetToggler/>에서 사용한 색상과 스위치의 SCS입니다.
$typeScriptBlue: #2f74c0;
$javaScriptYellow: #efd81c;
$width: 50px;
$height: 27px;
$lightColor: #ffffff;
$darkColor: #191919;

.switch {
    position: relative;
    text-align: center;
    display: inline-block;
    height: $height;

    & .switch-text {
      margin-top: 1rem;
      display: block;
    }

    & input {
        opacity: 0;
        width: 0;
        height: 0;
    }

    & .slider {
        width: $width;
        position: absolute;
        cursor: pointer;
        top: 0;
        left: 0;
        right: 0;
        bottom: 0;
        background-color: $lightColor;
        -webkit-transition: 0.4s;
        transition: 0.4s;
        margin: 0 auto;
    }

    & .slider:before {
        position: absolute;
        content: "";
        height: 19px;
        width: 20px;
        left: 4px;
        bottom: 4px;
        background-color: $darkColor;
        -webkit-transition: 0.4s;
        transition: 0.4s;
    }

    & input:checked + .slider {
        background-color: $darkColor;
    }
    & input:checked + .slider:before {
        background-color: $lightColor;
    }

    & input:focus + .slider {
        box-shadow: 0 0 1px $darkColor;
    }

    & input:checked + .slider:before {
        -webkit-transform: translateX(22px);
        -ms-transform: translateX(22px);
        transform: translateX(22px);
    }

    /* Rounded sliders */
    & .slider.round {
        border-radius: $height;
    }

    & .slider.round:before {
        border-radius: 50%;
    }
}

.switch.typescript {
    & .switch-text {
        color: $typeScriptBlue;
    }
    & .slider {
        background-color: $typeScriptBlue;
    }
}

.switch.javascript {
    & .switch-text {
        color: $javaScriptYellow;
    }
    & input:checked + .slider {
        background-color: $javaScriptYellow;
    }
}

작업 예


만일 네가 보고 혼자 놀고 싶다면, 나는 이미 a CodeSandbox의 전체 코드를 제공했다.SCSS는 가장 간단한 업무 예시이기 때문에 당연히 네가 내 블로그에서 본 스위치와 완전히 비슷하지는 않지만, 그것은 매우 가깝다.
나는 여전히 이 구성 요소의 미래 업무 계획을 가지고 있다.몇 가지 생각:
  • context 도구, 여기서 나는 내가 사용한 적이 있거나 전시한
  • 편의 블로그를 인용할 수 있다
  • description 아이템, 코드 세그먼트의 역할 간략 설명
  • usage 도구, 일부 실제 상하문에서 호출된 함수
  • id 도구, 그래서 나는 특정한 코드 세션에 연결할 수 있다. 왜냐하면 나는 the snippets page이 매우 길 것이라고 예상하기 때문이다.
  • 감사합니다!


    예전과 같이, 당신의 독서에 감사 드립니다. 나는 이 문장이 당신에게 유용하길 바랍니다.이제 파일을 원시 문자열로 가져오고 Gatsby와/또는 React에서 어떤 작업을 수행하는지 알 수 있습니다.
    건배!🍻
    - 크리스

    좋은 웹페이지 즐겨찾기