为嵌套文件夹运行npm install的最佳方法是什么?

WHI*_*LOR 94 node.js npm

npm packages在嵌套子文件夹中安装的最正确方法是什么?

my-app
  /my-sub-module
  package.json
package.json
Run Code Online (Sandbox Code Playgroud)

什么是有最好的方式packages/my-sub-module,当被自动安装npm install在运行my-app

Sco*_*ott 229

如果您知道嵌套子目录的名称,我更喜欢使用post-install.在package.json:

"scripts": {
  "postinstall": "cd nested_dir && npm install",
  ...
}
Run Code Online (Sandbox Code Playgroud)

  • @Emre应该可以工作,子shell可能会稍微清晰:"(cd nested_dir && npm install);(cd nested_dir2 && npm install); ..." (18认同)
  • 多个文件夹怎么样?"cd nested_dir && npm install && cd ..&cd nested_dir2 && npm install"?? (7认同)
  • @Emre 是的 - 就是这样。 (2认同)
  • @Scott 你不能把下一个文件夹放在 package.json 里面,就像每个文件夹的`"postinstall": "cd nested_dir2 && npm install"` 一样吗? (2认同)

小智 35

接受的答案有效,但您可以使用--prefix在选定位置运行 npm 命令。

"postinstall": "npm --prefix ./nested_dir install"
Run Code Online (Sandbox Code Playgroud)

并且--prefix适用于任何 npm 命令,而不仅仅是install.

您还可以使用以下命令查看当前前缀

npm prefix
Run Code Online (Sandbox Code Playgroud)

并设置您的全局安装(-g)文件夹

npm config set prefix "folder_path"
Run Code Online (Sandbox Code Playgroud)

也许TMI,但你明白了......


sno*_*zza 20

如果要运行单个命令在嵌套子文件夹中安装npm软件包,可以在根目录中通过npmmain 运行脚本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' })
})
Run Code Online (Sandbox Code Playgroud)

请注意,这是一个StrongLoop文章的示例,该文章专门针对模块化node.js项目结构(包括嵌套组件和package.json文件).

如建议的那样,您也可以使用bash脚本实现相同的功能.

编辑:使代码在Windows中工作

  • 虽然是的bash脚本会做,但我更喜欢nodejs这样做的方式,以便在具有DOS shell的Windows和具有Unix shell的Linux/Mac之间实现最大的可移植性. (3认同)
  • 不过,这很复杂,谢谢您的文章链接。 (2认同)

asd*_*ads 20

我的解决方案非常相似.Pure Node.js

以下脚本检查所有子文件夹(递归),只要它们具有package.jsonnpm 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))
}
Run Code Online (Sandbox Code Playgroud)

  • 您的脚本很好。但是,出于个人目的,我更喜欢删除第一个“如果条件”以获得深层嵌套的“ npm安装”! (3认同)

小智 12

编辑正如fgblomqvist在评论中提到的,npm现在也支持工作区:https ://docs.npmjs.com/cli/using-npm/workspaces

\n
\n

有些答案已经很老了。我认为现在我们有一些新的选项可用于设置monorepos

\n
    \n
  1. 我建议使用纱线工作区
  2. \n
\n
\n

工作区是一种设置包架构的新方法,从 Yarn 1.0 开始默认提供\xe2\x80\x99s。它允许您以这样的方式设置多个软件包,只需运行yarn install一次即可一次性安装所有软件包。

\n
\n
    \n
  1. 如果您更喜欢或必须继续使用npm,我建议您看看lerna
  2. \n
\n
\n

Lerna 是一个工具,可以优化使用 git 和 npm 管理多包存储库的工作流程。

\n
\n

lerna 也可以与纱线工作区完美配合 -文章。我刚刚完成了 monorepo 项目的设置 - example

\n

这是配置为使用 npm + lerna - MDC Web 的多包项目的示例:它们lerna bootstrap使用 package.json\'s运行postinstall

\n

  • 请不要使用 lerna,NPM 现在也对“工作区”提供本机支持:https://docs.npmjs.com/cli/v7/using-npm/workspaces/ (5认同)

Jel*_*ema 11

仅供参考,以防人们遇到这个问题。你现在可以:

  • 将package.json添加到子文件夹
  • 将此子文件夹作为参考链接安装在主package.json中:

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

  • 请注意,依赖项已安装在根文件夹中。我怀疑,即使您正在考虑使用这种模式,也希望得到子目录package.json的依赖关系。 (2认同)

dem*_*isx 11

根据@Scott的回答,只要知道子目录名称,install | postinstall脚本是最简单的方法。这就是我为多个子目录运行它的方式。例如,假设我们有api/web/shared/在monorepo根个子项目:

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

  • 在顶层运行 `npm install` 时出现此错误:`"(此时 cd 是意外的。"` (8认同)
  • 充分利用 `( )` 创建子 shell 并避免使用 `cd api && npm install && cd ..`。 (7认同)
  • 这应该是选定的答案! (4认同)
  • 我的目录相对于其父目录的嵌套深度相同,因此在我的情况下,我必须这样做:`"(cd api && npm install); (cd ../web && npm install);。 ..` 包括 `../` 以确保它将目录更改为正确的目录。我认为括号会在同一工作目录上下文中彼此独立地运行命令,正如 @CameronHudson 所说,但由于某种原因,它不适合我... (3认同)

Moh*_*mel 10

如果您find的系统上有实用程序,您可以尝试在应用程序根目录中运行以下命令:
find . ! -path "*/node_modules/*" -name "package.json" -execdir npm install \;

基本上,查找所有package.json文件并npm install在该目录中运行,跳过所有node_modules目录。


Don*_*ghn 9

我更喜欢postinstallnpm-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:*"
}
Run Code Online (Sandbox Code Playgroud)

  • 是的,您可以使用“&&”而不使用“run-p”。但正如你所说,这不太可读。另一个缺点(run-p 可以解决,因为安装是并行运行的)是如果一个脚本失败,则不会影响其他脚本 (2认同)