VSCode를 사용한 JavaScript 모듈 추출

배경



브라우저용 JavaScript의 개발에서도, BrowserifyWebpack와 같은 모듈 번들 툴을 만드는 것으로, 파일 단위로 모듈을 분할한 개발이 가능하게 되었습니다.

이미 있는 소스 코드를 모듈에 걸치는 조작은 기계적으로 실시할 수 있지만 번거롭습니다.
VSCode의 리팩토링 기능을 사용하면 기계적인 수고를 줄일 수 있습니다.

방법



참고 : 이번에는 이미 파일에 private static 함수가있는 상황을 대상으로합니다.
private static 함수를 추출하는 방법은 대상이 아닙니다.

대상 샘플



파일
아래와 같이 export하는 함수와는 별도로, private static 함수를 포함한 모듈이 있습니다.
이 private static 함수를 모듈로 추출합니다.

index.js
export default function(annotationData, modeAccordingToButton) {
  return function(selectionModel) {
    const modifications = selectionModel.all().map((e) => annotationData.getModificationOf(e).map((m) => m.pred))

    updateModificationButton(modeAccordingToButton, 'Negation', modifications)
    updateModificationButton(modeAccordingToButton, 'Speculation', modifications)
  }
}

function updateModificationButton(modeAccordingToButton, specified, modificationsOfSelectedElement) {
  // All modification has specified modification if exits.
  modeAccordingToButton[specified.toLowerCase()]
    .value(doesAllModificaionHasSpecified(specified, modificationsOfSelectedElement))
}

function doesAllModificaionHasSpecified(specified, modificationsOfSelectedElement) {
  if (modificationsOfSelectedElement.length < 0) {
    return false
  }

  return modificationsOfSelectedElement.length === modificationsOfSelectedElement.filter((m) => m.includes(specified)).length
}
updateModificationButton 함수와 doesAllModificaionHasSpecified 함수를 모듈로 추출합니다.

모듈 추출



updateModificationButton 함수



VSCode에서 개인 정적 함수에 초점을 맞추면 힌트 아이콘이 표시됩니다.
힌트 아이콘을 클릭하면 新しいファイルへ移動します라는 제안이 표시됩니다.



이것을 클릭하면 선택한 private static 함수가 다른 파일updateModificationButton.js로 나뉩니다.

updateModificationButton.js
import { doesAllModificaionHasSpecified } from "./index";
export function updateModificationButton(modeAccordingToButton, specified, modificationsOfSelectedElement) {
  // All modification has specified modification if exits.
  modeAccordingToButton[specified.toLowerCase()]
    .value(doesAllModificaionHasSpecified(specified, modificationsOfSelectedElement));
}

선택한 updateModificationButton 함수가 새로 작성된 updateModificationButton.js로 이동되었습니다.

index.js
import { updateModificationButton } from "./updateModificationButton";

export default function(annotationData, modeAccordingToButton) {
  return function(selectionModel) {
    const modifications = selectionModel.all().map((e) => annotationData.getModificationOf(e).map((m) => m.pred))

    updateModificationButton(modeAccordingToButton, 'Negation', modifications)
    updateModificationButton(modeAccordingToButton, 'Speculation', modifications)
  }
}

export function doesAllModificaionHasSpecified(specified, modificationsOfSelectedElement) {
  if (modificationsOfSelectedElement.length < 0) {
    return false
  }

  return modificationsOfSelectedElement.length === modificationsOfSelectedElement.filter((m) => m.includes(specified)).length
}

대신 index.js에는 import { updateModificationButton } from "./updateModificationButton"; 문장이 추가됩니다.

상호 import 문제



궁금한 점은 doesAllModificaionHasSpecified 함수 앞에 export가 추가 된 것입니다.updateModificationButton 함수 내에서 doesAllModificaionHasSpecified 함수를 사용하기 때문에 새로 만든 updateModificationButton.js에서 doesAllModificaionHasSpecified를 참조해야하기 때문입니다.
updateModificationButton.js를 확인하면 import { doesAllModificaionHasSpecified } from "./index"; 문이 있음을 알 수 있습니다.updateModificationButton.jsindex.js는 서로 import되어 기분이 좋지 않습니다.

doesAllModificaionHasSpecified



신경쓰지 않고 doesAllModificaionHasSpecified新しいファイルへ移動します.



그러면 doesAllModificaionHasSpecified 함수가 doesAllModificaionHasSpecified.js 파일에 알려집니다.updateModificationButton.js는 다음과 같이 수정됩니다.
import { doesAllModificaionHasSpecified } from "./doesAllModificaionHasSpecified";
export function updateModificationButton(modeAccordingToButton, specified, modificationsOfSelectedElement) {
  // All modification has specified modification if exits.
  modeAccordingToButton[specified.toLowerCase()]
    .value(doesAllModificaionHasSpecified(specified, modificationsOfSelectedElement));
}
updateModificationButton.jsdoesAllModificaionHasSpecified.js 를 참조하고 index.js 에 대한 참조는 없어졌습니다.
일차적으로 상호 import 문제는 ​​발생하지만, 모든 private static 함수를 모듈로 추출하면 자연스럽게 해소됩니다.

기타



하나의 함수를 export 할 때는 명명 된 내보내기보다 기본 내보내기가 더 바람직하다고 생각합니다.
다음과 같이 수정합니다.

index.js
import updateModificationButton from "./updateModificationButton";

export default function(annotationData, modeAccordingToButton) {
  return function(selectionModel) {
    const modifications = selectionModel.all().map((e) => annotationData.getModificationOf(e).map((m) => m.pred))

    updateModificationButton(modeAccordingToButton, 'Negation', modifications)
    updateModificationButton(modeAccordingToButton, 'Speculation', modifications)
  }
}

updateModificationButton.js
import doesAllModificaionHasSpecified from "./doesAllModificaionHasSpecified";

export default function(modeAccordingToButton, specified, modificationsOfSelectedElement) {
  // All modification has specified modification if exits.
  modeAccordingToButton[specified.toLowerCase()]
    .value(doesAllModificaionHasSpecified(specified, modificationsOfSelectedElement));
}

doesAllModificaionHasSpecified.js
export default function(specified, modificationsOfSelectedElement) {
  if (modificationsOfSelectedElement.length < 0) {
    return false;
  }
  return modificationsOfSelectedElement.length === modificationsOfSelectedElement.filter((m) => m.includes(specified)).length;
}

요약



VSCode의 리팩토링 기능을 사용하여 JavaScript의 파일 분할 수고를 줄일 수있었습니다.
이것은 Browserify나 Webpack을 사용한 모듈 분할의 혜택을 받기 쉬워집니다.
작은 독립 파일에 걸쳐서 다음과 같은 혜택을 누릴 수 있습니다.
  • 소스 코드의 영향 범위가 명확 해지고 수정하기 쉽습니다
  • 여러 사람이 수정 작업을 할 때 충돌이 일어나는 범위가 좁아진다

  • 참고



    JavaScript(ES2015)의 export 방법은 「명명된 내보내기」와 「기본 내보내기」의 2 종류 있어, import 할 때의 이름을 붙이는 방법이 다르다 - dev_dub의 블로그

    좋은 웹페이지 즐겨찾기