[node.js] 중첩 폴더에 대해 npm 설치를 실행하는 가장 좋은 방법은 무엇입니까?

npm packages중첩 된 하위 폴더 에 설치하는 가장 올바른 방법은 무엇입니까 ?

my-app
  /my-sub-module
  package.json
package.json

한하는 가장 좋은 방법은 무엇입니까 packages/my-sub-module경우 자동으로 설치 npm install에서 실행은 my-app?



답변

단일 명령을 실행하여 중첩 된 하위 폴더에 npm 패키지를 설치하려면 루트 디렉터리에서 npm및 main package.json을 통해 스크립트를 실행할 수 있습니다 . 스크립트는 모든 하위 디렉토리를 방문하여 npm install.

다음은 .js원하는 결과를 얻을 수 있는 스크립트입니다.

var fs = require('fs')
var resolve = require('path').resolve
var join = require('path').join
var cp = require('child_process')
var os = require('os')

// get library path
var lib = resolve(__dirname, '../lib/')

fs.readdirSync(lib)
  .forEach(function (mod) {
    var modPath = join(lib, mod)
// ensure path has package.json
if (!fs.existsSync(join(modPath, 'package.json'))) return

// npm binary based on OS
var npmCmd = os.platform().startsWith('win') ? 'npm.cmd' : 'npm'

// install folder
cp.spawn(npmCmd, ['i'], { env: process.env, cwd: modPath, stdio: 'inherit' })
})

이것은 모듈 식 프로젝트 구조 (중첩 된 구성 요소 및 파일 포함) 를 구체적으로 다루는 StrongLoop 기사 에서 가져온 예제 입니다.node.jspackage.json

제안 된대로 bash 스크립트로도 동일한 결과를 얻을 수 있습니다.

편집 : Windows에서 코드 작동


답변

중첩 된 하위 디렉터리의 이름을 알고 있다면 설치 후 사용하는 것을 선호합니다. 에서 package.json:

"scripts": {
  "postinstall": "cd nested_dir && npm install",
  ...
}


답변

@Scott의 대답에 따르면 install | postinstall 스크립트는 하위 디렉토리 이름을 알고있는 한 가장 간단한 방법입니다. 이것이 여러 하위 디렉토리에 대해 실행하는 방법입니다. 예를 들어, monorepo 루트에 api/, web/shared/하위 프로젝트가 있다고 가정합니다.

// In monorepo root package.json
{
...
 "scripts": {
    "postinstall": "(cd api && npm install); (cd web && npm install); (cd shared && npm install)"
  },
}


답변

내 솔루션은 매우 유사합니다. 순수 Node.js

다음 스크립트 는 각 하위 폴더가 package.json있고 실행 npm install되는 한 모든 하위 폴더를 (재귀 적으로) 검사 합니다. 예외를 추가 할 수 있습니다. 폴더에 package.json. 아래 예에서 이러한 폴더 중 하나는 “packages”입니다. “사전 설치”스크립트로 실행할 수 있습니다.

const path = require('path')
const fs = require('fs')
const child_process = require('child_process')

const root = process.cwd()
npm_install_recursive(root)

// Since this script is intended to be run as a "preinstall" command,
// it will do `npm install` automatically inside the root folder in the end.
console.log('===================================================================')
console.log(`Performing "npm install" inside root folder`)
console.log('===================================================================')

// Recurses into a folder
function npm_install_recursive(folder)
{
    const has_package_json = fs.existsSync(path.join(folder, 'package.json'))

    // Abort if there's no `package.json` in this folder and it's not a "packages" folder
    if (!has_package_json && path.basename(folder) !== 'packages')
    {
        return
    }

    // If there is `package.json` in this folder then perform `npm install`.
    //
    // Since this script is intended to be run as a "preinstall" command,
    // skip the root folder, because it will be `npm install`ed in the end.
    // Hence the `folder !== root` condition.
    //
    if (has_package_json && folder !== root)
    {
        console.log('===================================================================')
        console.log(`Performing "npm install" inside ${folder === root ? 'root folder' : './' + path.relative(root, folder)}`)
        console.log('===================================================================')

        npm_install(folder)
    }

    // Recurse into subfolders
    for (let subfolder of subfolders(folder))
    {
        npm_install_recursive(subfolder)
    }
}

// Performs `npm install`
function npm_install(where)
{
    child_process.execSync('npm install', { cwd: where, env: process.env, stdio: 'inherit' })
}

// Lists subfolders in a folder
function subfolders(folder)
{
    return fs.readdirSync(folder)
        .filter(subfolder => fs.statSync(path.join(folder, subfolder)).isDirectory())
        .filter(subfolder => subfolder !== 'node_modules' && subfolder[0] !== '.')
        .map(subfolder => path.join(folder, subfolder))
}


답변

사람들이이 질문을 보게 될 경우를 대비하여 참고 용입니다. 이제 다음을 수행 할 수 있습니다.

  • 하위 폴더에 package.json 추가
  • 이 하위 폴더를 기본 package.json에 참조 링크로 설치합니다.

npm install --save path/to/my/subfolder


답변

사용 사례 1 : 각 하위 디렉터리 (각 package.json이있는)에서 npm 명령을 실행하려면 다음을 사용해야합니다.postinstall .

npm-run-all어쨌든 자주 사용 하기 때문에 멋지고 짧게 유지하기 위해 사용합니다 (설치 후 부분).

{
    "install:demo": "cd projects/demo && npm install",
    "install:design": "cd projects/design && npm install",
    "install:utils": "cd projects/utils && npm install",

    "postinstall": "run-p install:*"
}

한 번에 또는 개별적으로 설치할 수있는 추가 이점이 있습니다. 필요하지 않거나 원하지 않는 경우npm-run-all 종속성으로 demisx의 답변을 확인하십시오 (설치 후 하위 셸 사용).

사용 사례 2 : 루트 디렉터리에서 모든 npm 명령을 실행하려는 경우 (예를 들어 하위 디렉터리에서 npm 스크립트를 사용하지 않을 것임) 종속성과 같이 각 하위 디렉터리를 간단히 설치할 수 있습니다.

npm install path/to/any/directory/with/a/package-json

후자의 경우 하위 디렉토리에서 node_modules또는 package-lock.json파일을 찾을 수 없다는 사실에 놀라지 마십시오. 모든 패키지가 root에 설치 node_modules되므로 npm 명령을 실행할 수 없습니다. 종속 항목이 필요합니다).

확실하지 않은 경우 사용 사례 1은 항상 작동합니다.


답변

snozza의 답변에 Windows 지원을 추가 하고 node_modules폴더가있는 경우 건너 뜁니다 .

var fs = require('fs')
var resolve = require('path').resolve
var join = require('path').join
var cp = require('child_process')

// get library path
var lib = resolve(__dirname, '../lib/')

fs.readdirSync(lib)
  .forEach(function (mod) {
    var modPath = join(lib, mod)
    // ensure path has package.json
    if (!mod === 'node_modules' && !fs.existsSync(join(modPath, 'package.json'))) return

    // Determine OS and set command accordingly
    const cmd = /^win/.test(process.platform) ? 'npm.cmd' : 'npm';

    // install folder
    cp.spawn(cmd, ['i'], { env: process.env, cwd: modPath, stdio: 'inherit' })
})