npx

devAnderson·2021년 12월 29일
0

TIL

목록 보기
1/106

1. 나오게 된 근원

  • npm은 사람들이 만들어 놓은 코드들을 패키지별로 묶어서 마치 "상품을 구매하듯" 모듈형태로 가져올 수 있는 시스템이다.

  • 이 npm의 문제는, 서로의 의존성이 엮여있는 dependency tree의 특성상 버전을 하나하나 다 맞춰주기가 어렵다는 점이다.

    예를 들어, 어떤 프로젝트 환경을 위해 a라고 하는 패키지와 b라고 패키지가 둘 다 필요할 때, 이 두 패키지가 서로 의존한다면 버전을 맞춰야 한다.
    이렇게 서로가 의존하고 있는 패키지들의 수가 많아지만 많아질수록 버전관리가 어려워지게 된다.

  • 따라서 특정 개발환경을 위해 패키지들을 버전별로 모아 엮어서 배포하는 시스템이 바로 npx이다.

2. 탐색 경로

  1. 우선 npx를 통해 커맨드를 입력하면, 해당 working directory 기준으로 올라가며 node_modules 폴더를 찾는다

  2. 그 후, 그 내부를 재귀적으로 읽어나가며 bin 폴더들을 찾아낸 뒤, npx 뒤에 입력된 명령어와 동일한 이름의 파일을 찾는다.

    만약 루트경로까지 올라가면서 찾지 못했다면 npm 시스템에서 찾기 시작한다.
    참고로 npx 역시 커맨드의 일종으로, bin 폴더 안에서 npx 라는 이름의 파일을 찾아낸 뒤, 실행되고 있다.

  3. 찾게 된다면, "yargs" 라고 하는 패키지를 이용하여 npx 뒤의 커맨드라인을 분리한 후 배열로 담아 process.argv 에 할당한다.

    기본적으로 process.argv를 확인해보면, 거기에는 배열이 설정되어 있는데
    0번째는 사용되는 node와 관련된 명령어 집합 폴더인 bin의 위치,
    1번째는 해당 working directory 기준으로 node module을 찾았을 때 그 안의 .bin 폴더 내부에 존재하는 cli 명령어에 대한 경로가 오고,
    그 이후부터는 추가적으로 cli에 붙어서 따라오는 스트링값들이 온다.

// 예를들어, "npx codestates-submission lse 10-01" 를 커맨드로 쳐봤을 때,
// ./node_modules/.bin/codestates-submission.js 파일 안에서 
// console.log(process.argv)를 찍어보면

[
  '/Users/devanderson/.nvm/versions/node/v16.13.0/bin/node',
  '/Users/devanderson/Documents/states/test/testing/node_modules/.bin/codestates-submission',
  'lse',
  '10-01'
]
이런식으로 나오게 된다. 

만약, yargs 패키지를 사용한다면, 해당 내용에 대해서 yargs 패키지만의 독자적인 형태로 정리가 된다.

const yargs = require('yargs');

console.log(yargs.argv);

// result 
 _: [ 'lse', '10-01' ],
  '$0': '/Users/devanderson/Documents/states/test/testing/node_modules/.bin/codestates-submission'
}

뭔가 달라진 것을 알 수 있다.
언더바 형태의 키에 원래 process.argv에 0번째와 1번째에 있던 경로정보를 제외한 나머지값이 할당된 것을 볼 수 있다.
  • 즉, "npx codestates-submission lse 10-01" 라고 터미널에 쳐서 실행하는 순간,

  • bin 폴더에 저장된 npx 폴더로 가서, 거기에있는 내용에 따라 exec를 실행하고

  • 이 exec는 자동으로 커맨드를 입력하고 있는 working directory를 기준으로 상위로 올라가면서 node_modules 폴더를 찾고

  • 이 폴더 내에서 재귀적으로 bin 폴더를 확인해나간다 그리고 그 안에서 "codestates-submission" 이름을 가진 파일을 찾은 후,

  • process.argv와 만약 yargs를 사용한다면 yargs.argv 안에다가 필요한 나머지 cli strings을 저장하면서 해당 js 파일을 실행한다.

  • 해당 js 파일은 이제 cli 명령어의 리스트를 배열로 가져올 수 있으므로, 이것을 활용하여 js가 돌아가게 하면 된다.

  • 예를들어,

// node_modules/@codestates-cc/submisstion-npm/submisstion-npm/.bin/codestates-submission.js

const yargs = require('yargs');
const lib = require('../lib/')
console.log(process.argv,"-----------------------", yargs.argv)

const ls = require('../lib/ls')

const argv = require('yargs/yargs')(process.argv.slice(2)).argv;
console.log("!~!~!~!~!~!~!~!~!~! changed with all",argv)

const firstArgs = argv._.length > 0 && argv._[0]
const secondArgs = argv._.length >= 2 && argv._[1];
const changeDate = (()=>{
  const [month,date] = secondArgs.split("-");
   return `2021-${month}-${date}T19:11:35.957Z`
})()

if(argv.ls || firstArgs) {
  ls(changeDate)
}
else {
  lib()
}
//node_modules/@codestates-cc/submisstion-npm/submisstion-npm/lib/ ls.js

const { existsSync, readFileSync } = require("fs");
const { requestDevice, getUser } = require("./github");
const path = require("path");
const homedir = require("os").homedir();
const endpoint =
  "https://2j12cf7y29.execute-api.ap-northeast-2.amazonaws.com/dev/sprint/ls";
const { get } = require("axios");

const ls = (user, from) => {
  return get(`${endpoint}?user=${user}`).then(({ data }) => {
    if (data.responseTrial.length === 0) {
      console.log("제출 기록이 없습니다.");
      return;
    }

    const result = data.responseTrial.reduce((arr, record) => {
      return record.assessments.reduce((arr, asmt) => {
        return [
          ...arr,
          {
            name: record.name,
            // user: record.user,
            timestamp: asmt.timestamp,
            // result: asmt.result
          },
        ];
      }, arr);
    }, []);

    const section3 = from;
    const mySubmitSorted = result
      .sort((a, b) => {
        return Date.parse(a.timestamp) - Date.parse(b.timestamp);
      })
      .filter((el) => {
        if (Date.parse(el.timestamp) > Date.parse(section3)) return true;
      });
    console.log("------- Section3 Started! -------");
    console.log(mySubmitSorted.map((el) => `${el.timestamp}    ${el.name}`));
  });
};

const entryPoint = (secondArgs) => {
  const location = path.join(homedir, ".codestates-token");
  if (existsSync(location)) {
    const token = readFileSync(location).toString();
    getUser(token.split("\n")[0], ({ data }) => {
      console.log(data.login + "님의 제출 기록입니다.");
      ls(data.id, secondArgs);
    });
  } else {
    requestDevice(({ data }) => {
      console.log(data.login + "님의 제출 기록입니다.");
      ls(data.id, secondArgs);
    });
  }
};

module.exports = entryPoint;
// entryPoint()
  • 참고로, npx는 위로 올라가면서 node_modules라는 이름의 파일을 탐색해가면서 원하는 조건을 찾다가 못찾으면,
  • npm에 등록되어 있는 레지스트리에서까지 해당 내용을 찾는다.
  • 그리고 나서 내용을 찾으면 그것을 설치하고 실행하지만 만약 찾지 못한다면
npm ERR! code E404
npm ERR! 404 Not Found - GET https://registry.npmjs.org/codestates-submission - Not found

.
.
.
  • 이렇게 에러를 낸다. 위에서 볼 수 있듯, 찾지를 못해서 registry 서버에까지 확인해보려고하는데 없으니까 못찾았다고 에러를 발생시킨다.
profile
자라나라 프론트엔드 개발새싹!

0개의 댓글