데노 시작하기

데노



DenoV8에 구축된 새로운 JavaScript 런타임입니다.

Deno는 ESM을 사용하여 JavaScript 모듈을 로드하고 기본적으로 fetch()과 같은 브라우저 API를 지원합니다. 그것의 permissions 와 함께 이것은 Deno를 웹 서버를 구축하기 위한 도구가 아니라 스크립팅 가능한 웹 클라이언트처럼 느끼게 합니다.

Deno 실행 파일은 Rust로 빌드되었습니다. 이것은 구현 세부 사항처럼 보일 수 있지만 Deno를 Rust 프로그램 내부에 JavaScript를 내장하는 도구로 설명할 수도 있습니다.

이 기사에서는 Deno를 사용하는 첫 번째 단계에 대해 설명합니다.

시작하기



Deno는 installed에서 경로의 위치로 릴리스를 복사하여 GitHub이 될 수 있습니다. 다음과 같이 환경을 구성했습니다.

export DENO_DIR=~/deno
export PATH=${PATH}:${DENO_DIR}/bin


설치되면 deno --version는 설치된 버전을 표시하고 deno upgrade는 바이너리를 최신 릴리스로 업그레이드합니다. deno help는 다른 명령의 사용법을 보여줍니다.

IDE 지원 및 디버깅을 위해 DenoVS Code extension를 설치하는 것이 좋습니다. manuallaunch config 을 제안했는데 대부분 저에게 효과적이었습니다.



hello.js



내 첫 번째 Deno 프로그램인 hello.js 이 있습니다. deno run hello.js args...로 실행할 수 있습니다.

const hello = 'Hello Deno';
console.log(`${hello} %s hello %o`, new Date(), Deno.args);

const buf = new TextEncoder().encode('-🦀-\n');
await Deno.stdout.write(buf);
console.table(buf);


stdout에 쓰는 가장 쉬운 방법은 내장된 console.log()를 사용하는 것입니다.

Deno 내부 구조에 대해 궁금한 분들을 위해:
  • 전역console 개체가 runtime/js/99_main.js에 생성됩니다.
  • console.log() 방법은 runtime/js/02_console.js 에 있습니다.
  • 이는 core/bindings.rs 에서 녹 함수core.print를 호출합니다.

  • Deno.stdout은 낮은 수준의 스트림 인터페이스를 제공합니다. 'Deno.stdout.write()'에 의해 반환된 약속의 await에 주목하십시오.

    타자기



    위의 코드도 유효합니다TypeScript. Deno에는 내장 TypeScript 컴파일러가 포함되어 있으므로 간단히 hello.js의 이름을 hello.ts로 바꾸면 동일한 방식으로 작동합니다.

    DenoStandard Librarybuilt-ins에 대한 선언(및 자동 생성 문서)과 마찬가지로 대부분 TypeScript로 작성되었으므로 JavaScript 작성을 선호하더라도 약간의 TypeScript 구문을 알면 도움이 됩니다.

    VS Code에서 코드 완성에 가장 유용한 TypeScript 선언을 찾았습니다.

    scan.js



    Deno를 웹 클라이언트로 활용하는 정신으로 간단한 링크 유효성 검사기를 구축해 보기로 했습니다. HTML을 구문 분석하려면 타사 라이브러리가 필요합니다.

    라이브러리 작성자가 deno 호환 ESM 모듈을 게시하기 위해 GitHub 저장소를 등록할 수 있는 deno.land/x에서 (아직) 사용할 수 없는 경우에도 인기 있는 npm 모듈이 최선의 방법이라고 가정하고 검색을 시작했습니다.

    약간의 인터넷 검색 후, 광범위하게 사용되며 핵심에서 간단한 저수준 트리 API를 제공하는 parse5에 도달했습니다.

    또한 npm 패키지를 ESM 모듈로 제공하도록 특별히 설계된 CDN인 Skypack 에 대해서도 들었습니다. skypack.dev에 대한 빠른 검색과 Deno에서 작동하는 parse5 모듈에 대한 URL이 있었습니다.

    scan.js의 코드는 웹 사이트를 크롤링하여 동일한 출처를 가리키는 사이트의 모든 링크를 가져올 수 있는지 확인합니다.

    import parse5 from "https://cdn.skypack.dev/parse5?dts";
    
    const rootUrl = Deno.args[0];
    if (!rootUrl) exit(1, "Please provide a URL");
    
    const rootOrigin = new URL(rootUrl).origin;
    
    const urlMap = {}; // tracks visited urls
    
    await checkUrl(rootUrl);
    const result = Object.entries(urlMap).filter((kv) => kv[1] !== "OK");
    
    if (result.length) {
      exit(1, result);
    } else {
      exit(0, "🎉 no broken links found.");
    }
    
    // recursively checks url and same-origin urls inside
    // resolves when done
    async function checkUrl(url, base) {
      base = base || url;
      try {
        // parse the url relative to base
        const urlObj = new URL(url, base);
    
        // ignore query params and hash
        const href = urlObj.origin + urlObj.pathname;
    
        // only process same-origin urls
        if (!urlMap[href] && urlObj.origin === rootOrigin) {
          // fetch from href
          urlMap[href] = "pending";
          const res = await fetch(href);
    
          // bail out if fetch was not ok
          if (!res.ok) {
            urlMap[href] = { status: res.status, in: base };
            return;
          }
    
          urlMap[href] = "OK";
    
          // check content type
          if (!res.headers.get("content-type").match(/text\/html/i)) return;
    
          // parse response
          console.log("parsing", urlObj.pathname);
          const html = await res.text();
          const document = parse5.parse(html);
    
          // scan for <a> tags and call checkURL for each, with base = href
          const promises = [];
          scan(document, "a", (node) => {
            promises.push(checkUrl(attr(node, "href"), href));
          });
          await Promise.all(promises);
        }
      } catch (err) {
        urlMap[url] = { error: err.message, in: base };
      }
    }
    
    // return value of attr with name for a node
    function attr(node, name) {
      return node.attrs.find((attr) => attr.name === name)?.value;
    }
    
    // recursive DOM scan
    // calls fn(node) on nodes matching tagName
    function scan(node, tagName, fn) {
      if (node?.tagName === tagName) {
        fn(node);
      }
      if (!node.childNodes) return;
      for (const childNode of node.childNodes) {
        scan(childNode, tagName, fn);
      }
    }
    
    function exit(code, msg) {
      console.log(msg);
      Deno.exit(code);
    }
    


    이 스크립트는 https://deno-hello.jldec.me/을 사용하여 Cloudflare Pages에서 호스팅됩니다.

    실행하려면 deno run --allow-net SCRIPT URL로 전화하십시오. 예를 들어

    $ deno run --allow-net https://deno-hello.jldec.me/scan.js https://jldec.me
    
    parsing /
    parsing /getting-started-with-deno
    parsing /first-steps-using-cloudflare-pages
    parsing /calling-rust-from-a-cloudflare-worker
    parsing /a-web-for-everyone
    parsing /why-serverless-at-the-edge
    parsing /fun-with-vercel
    parsing /migrating-from-cjs-to-esm
    parsing /forays-from-node-to-rust
    parsing /about
    parsing /github-actions-101
    parsing /spring-boot-101
    parsing /why-the-web-needs-better-html-editing-components
    
    🎉 no broken links found.
    


    참고: 이 첫 번째 구현의 경우 대기열이 없으므로 대규모 사이트를 가리키지 않는 것이 좋습니다.

    컴파일



    deno 경험은 여전히 ​​군데군데 다소 거칠게 느껴지지만 제가 정말 좋아하는 한 가지 새로운 기능은 스크립트를 독립 실행 파일로 만드는 기능입니다compile.

    $ deno --unstable compile --allow-net scan.js
    Bundle file:./scan.js
    Compile file:./scan.js
    Emit scan
    


    이제 Deno를 설치하거나 특별한 옵션을 기억하지 않고도 scan에 전화할 수 있습니다.

    $ ./scan
    Please provide a URL
    
    $ ./scan https://jldec.fun
    ...
    🎉 no broken links found.
    


    좋은 웹페이지 즐겨찾기