Cài đặt các phụ thuộc trên toàn cầu và cục bộ bằng gói.json


189

Sử dụng npm chúng ta có thể cài đặt các mô-đun trên toàn cầu bằng cách sử dụng -gtùy chọn. Làm thế nào chúng ta có thể làm điều này trong tệp pack.json?

Giả sử, đây là những phụ thuộc của tôi trong tệp pack.json

"dependencies": {
    "mongoose": "1.4.0",
    "node.io" : "0.3.3",
    "jquery"  : "1.5.1",
    "jsdom"   : "0.2.0",
    "cron"    : "0.1.2"
  }

Khi tôi chạy npm install, tôi chỉ muốn node.iođược cài đặt trên toàn cầu, phần còn lại nên được cài đặt cục bộ. Có một lựa chọn cho điều này?


11
Bạn không thể. Tuy nhiên, bạn có thể đặt "preferGlobal": truebên trong pack.json cho một mô-đun.
Raynos

vâng, tôi biết về <code> preferGlobal </ code>, nhưng điều đó sẽ cài đặt tất cả các phụ thuộc trên toàn cầu ... dù sao cũng cảm ơn! tôi đoán là không có tính năng nào như thế ...
Madhusudhan

3
Tôi không nghĩ rằng nó làm. Nó cài đặt các mô-đun hiện tại một cách hả hê. Nếu một phụ thuộc riêng lẻ được đặt thành đúng, nó cũng có thể được cài đặt trên toàn cầu. Thực sự bạn chỉ nên hỏi @isaacs trong # node.js
Raynos

3
Cài đặt toàn cầu có thể tạo ra địa ngục phụ thuộc. Giả sử gói A cần phiên bản 0.3.3 và gói B phiên bản 0.3.4 và cả hai đều không hoạt động với phiên bản khác. Sau đó, bạn cần hai máy để chứa hai gói.
nalply

6
không có ý kiến ​​nào trong số này giúp tôi giải quyết vấn đề này ... thật tuyệt nếu mã của bạn chỉ cho tôi nhiều hơn là "preferGlobal":true... tôi thực sự không biết nên đặt cái này ở đâu trong pack.json. npmjs.org/doc/json.html Tài liệu NPM nói rằng preferGlobal dành cho gói riêng của bạn và cài đặt đó sẽ khiến nó cài đặt gói của riêng bạn dưới dạng toàn cầu. có vẻ như nhiều hơn một hướng dẫn, mặc dù.
PPPaul

Câu trả lời:


216

Lưu ý mới: Bạn có thể không muốn hoặc không cần phải làm điều này. Những gì bạn có thể muốn làm chỉ là đặt các loại phụ thuộc lệnh đó để xây dựng / kiểm tra, v.v. trong devDependenciesphần của gói.json của bạn. Bất cứ khi nào bạn sử dụng một cái gì đó từ scriptstrong gói.json, các lệnh devDependencies của bạn (trong node_modules / .bin) hoạt động như thể chúng nằm trong đường dẫn của bạn.

Ví dụ:

npm i --save-dev mocha # Install test runner locally
npm i --save-dev babel # Install current babel locally

Sau đó, trong gói.json:

// devDependencies has mocha and babel now

"scripts": {
  "test": "mocha",
  "build": "babel -d lib src",
  "prepublish": "babel -d lib src"
}

Sau đó, tại dấu nhắc lệnh của bạn, bạn có thể chạy:

npm run build # finds babel
npm test # finds mocha

npm publish # will run babel first

Nhưng nếu bạn thực sự muốn cài đặt trên toàn cầu, bạn có thể thêm cài đặt sẵn trong phần tập lệnh của gói.json:

"scripts": {
  "preinstall": "npm i -g themodule"
}

Vì vậy, thực sự cài đặt npm của tôi thực thi cài đặt npm một lần nữa .. thật kỳ lạ nhưng dường như hoạt động.

Lưu ý: bạn có thể gặp sự cố nếu bạn đang sử dụng thiết lập phổ biến nhất cho npmyêu cầu cài đặt gói Node toàn cầu sudo. Một tùy chọn là thay đổi npmcấu hình của bạn để điều này không cần thiết:

npm config set prefix ~/npm, thêm $ HOME / npm / bin vào $ PATH bằng cách thêm export PATH=$HOME/npm/bin:$PATHvào ~/.bashrc.


3
Tôi không thể làm việc này với npm i -g underscore-cli. nó đưa ra một cảnh báo về việc wd bị sai. wd có nghĩa là thư mục làm việc, tôi đoán. Khi tôi tự làm điều này trên dòng lệnh thì mọi thứ sẽ ổn, tuy nhiên tôi sẽ thích hơn nếu người dùng có thể xử lý việc cài đặt mã của tôi một cách đơn giảnnpm install
PPPaul

3
PPPaul - Tôi đã gặp vấn đề tương tự khi tôi thử lại thủ thuật này gần đây. Có thể thiết lập của tôi khác bây giờ hoặc nó chỉ hoạt động với các mô-đun nhất định. Nếu không, tôi đoán một cái gì đó thay đổi với npm?
Jason Livesay

9
Ngoài ra, bạn có thể kiểm tra trước nếu gói đã được cài đặt: npm list module -g || npm install module -gvì npm sẽ trả về giá trị thoát thích hợp.
m90

3
@CMCDragonkai: Đây thực sự nên là một câu hỏi riêng biệt. Nhưng, bạn đặt các lệnh của mình trong một tập lệnh và chỉ định tập lệnh là lệnh để thực thi (như "preinstall" : "scripts/preinstall.sh").
Chúng tôi là tất cả Monica

1
&&Ví dụnpm install -g bower && npm install -g grunt-cli
@CMCDragonkai kết

12

Do những nhược điểm được mô tả dưới đây, tôi khuyên bạn nên làm theo câu trả lời được chấp nhận:

Sử dụng npm install --save-dev [package_name]sau đó thực thi các tập lệnh với:

$ npm run lint
$ npm run build
$ npm test

Câu trả lời ban đầu của tôi nhưng không được đề nghị sau đây.


Thay vì sử dụng cài đặt toàn cầu, bạn có thể thêm gói vào devDependencies( --save-dev) và sau đó chạy tệp nhị phân từ bất kỳ đâu trong dự án của bạn:

"$(npm bin)/<executable_name>" <arguments>...

Trong trường hợp của bạn:

"$(npm bin)"/node.io --help

Kỹ sư này đã cung cấp một npm-execbí danh như một phím tắt. Kỹ sư này sử dụng một shellscript gọi là env.sh. Nhưng tôi thích sử dụng $(npm bin)trực tiếp, để tránh bất kỳ tập tin bổ sung hoặc thiết lập.

Mặc dù nó làm cho mỗi cuộc gọi lớn hơn một chút, nhưng nó chỉ nên hoạt động , ngăn chặn:

  • xung đột phụ thuộc tiềm năng với các gói toàn cầu (@nalply)
  • sự cần thiết cho sudo
  • sự cần thiết phải thiết lập một tiền tố npm (mặc dù tôi vẫn khuyên bạn nên sử dụng một tiền tố)

Nhược điểm:

  • $(npm bin) sẽ không hoạt động trên Windows.
  • Các công cụ sâu hơn trong cây dev của bạn sẽ không xuất hiện trong npm binthư mục. (Cài đặt npm-run hoặc npm-which để tìm chúng.)

Có vẻ như một giải pháp tốt hơn là đặt các tác vụ phổ biến (như xây dựng và thu nhỏ) trong phần "tập lệnh" của bạn package.json, như Jason trình bày ở trên.


Thêm một bí danh trong của bạn .bashrcđể dễ dàng thêm bin/thư mục vào PATHbiến môi trường của bạn : alias nodebin='export PATH=$(npm bin)/:$PATH'. Thực thi nodebinvà sau đó bạn có thể chỉ cần gõ các lệnh của bạn như bình thường.
gitaarik

Tôi không biết tại sao nó không hoạt động cho các đội. Tất nhiên bạn cần phải thiết lập nó và nếu bạn không muốn sử dụng bí danh đó là lựa chọn của bạn. Nhưng nó không thể làm tổn thương khi sử dụng nó trong một nhóm.
gitaarik

9

Điều này hơi cũ nhưng tôi gặp phải yêu cầu nên đây là giải pháp tôi đưa ra.

Vấn đề:

Nhóm phát triển của chúng tôi duy trì nhiều sản phẩm ứng dụng web .NET mà chúng tôi đang chuyển sang AngularJS / Bootstrap. VS2010 không dễ dàng cho vay các quy trình xây dựng tùy chỉnh và các nhà phát triển của tôi thường xuyên làm việc trên nhiều bản phát hành sản phẩm của chúng tôi. VCS của chúng tôi là Subversion (tôi biết, tôi biết. Tôi đang cố gắng chuyển sang Git nhưng nhân viên tiếp thị phiền phức của tôi rất khắt khe) và một giải pháp VS duy nhất sẽ bao gồm một số dự án riêng biệt. Tôi cần nhân viên của mình có một phương pháp chung để khởi tạo môi trường phát triển của họ mà không phải cài đặt cùng các gói Node (gulp, bower, v.v.) nhiều lần trên cùng một máy.

TL; DR:

  1. Cần "npm install" để cài đặt môi trường phát triển Node / Bower toàn cầu cũng như tất cả các gói yêu cầu cục bộ cho một sản phẩm .NET.

  2. Các gói toàn cầu chỉ nên được cài đặt nếu chưa được cài đặt.

  3. Liên kết cục bộ đến các gói toàn cầu phải được tạo tự động.

Giải pháp:

Chúng tôi đã có một khung phát triển chung được chia sẻ bởi tất cả các nhà phát triển và tất cả các sản phẩm vì vậy tôi đã tạo một tập lệnh NodeJS để cài đặt các gói toàn cầu khi cần và tạo các liên kết cục bộ. Tập lệnh nằm trong ".... \ SharedFiles" liên quan đến thư mục cơ sở của sản phẩm:

/*******************************************************************************
* $Id: npm-setup.js 12785 2016-01-29 16:34:49Z sthames $
* ==============================================================================
* Parameters: 'links' - Create links in local environment, optional.
* 
* <p>NodeJS script to install common development environment packages in global
* environment. <c>packages</c> object contains list of packages to install.</p>
* 
* <p>Including 'links' creates links in local environment to global packages.</p>
* 
* <p><b>npm ls -g --json</b> command is run to provide the current list of 
* global packages for comparison to required packages. Packages are installed 
* only if not installed. If the package is installed but is not the required 
* package version, the existing package is removed and the required package is 
* installed.</p>.
*
* <p>When provided as a "preinstall" script in a "package.json" file, the "npm
* install" command calls this to verify global dependencies are installed.</p>
*******************************************************************************/
var exec = require('child_process').exec;
var fs   = require('fs');
var path = require('path');

/*---------------------------------------------------------------*/
/* List of packages to install and 'from' value to pass to 'npm  */
/* install'. Value must match the 'from' field in 'npm ls -json' */
/* so this script will recognize a package is already installed. */
/*---------------------------------------------------------------*/
var packages = 
  {
  "bower"                      :                      "bower@1.7.2", 
  "event-stream"               :               "event-stream@3.3.2",
  "gulp"                       :                       "gulp@3.9.0",
  "gulp-angular-templatecache" : "gulp-angular-templatecache@1.8.0",
  "gulp-clean"                 :                 "gulp-clean@0.3.1", 
  "gulp-concat"                :                "gulp-concat@2.6.0",
  "gulp-debug"                 :                 "gulp-debug@2.1.2",
  "gulp-filter"                :                "gulp-filter@3.0.1",
  "gulp-grep-contents"         :         "gulp-grep-contents@0.0.1",
  "gulp-if"                    :                    "gulp-if@2.0.0", 
  "gulp-inject"                :                "gulp-inject@3.0.0", 
  "gulp-minify-css"            :            "gulp-minify-css@1.2.3",
  "gulp-minify-html"           :           "gulp-minify-html@1.0.5",
  "gulp-minify-inline"         :         "gulp-minify-inline@0.1.1",
  "gulp-ng-annotate"           :           "gulp-ng-annotate@1.1.0",
  "gulp-processhtml"           :           "gulp-processhtml@1.1.0",
  "gulp-rev"                   :                   "gulp-rev@6.0.1",
  "gulp-rev-replace"           :           "gulp-rev-replace@0.4.3",
  "gulp-uglify"                :                "gulp-uglify@1.5.1",
  "gulp-useref"                :                "gulp-useref@3.0.4",
  "gulp-util"                  :                  "gulp-util@3.0.7",
  "lazypipe"                   :                   "lazypipe@1.0.1",
  "q"                          :                          "q@1.4.1",
  "through2"                   :                   "through2@2.0.0",

  /*---------------------------------------------------------------*/
  /* fork of 0.2.14 allows passing parameters to main-bower-files. */
  /*---------------------------------------------------------------*/
  "bower-main"                 : "git+https://github.com/Pyo25/bower-main.git" 
  }

/*******************************************************************************
* run */
/**
* Executes <c>cmd</c> in the shell and calls <c>cb</c> on success. Error aborts.
* 
* Note: Error code -4082 is EBUSY error which is sometimes thrown by npm for 
* reasons unknown. Possibly this is due to antivirus program scanning the file 
* but it sometimes happens in cases where an antivirus program does not explain 
* it. The error generally will not happen a second time so this method will call 
* itself to try the command again if the EBUSY error occurs.
* 
* @param  cmd  Command to execute.
* @param  cb   Method to call on success. Text returned from stdout is input.
*******************************************************************************/
var run = function(cmd, cb)
  {
  /*---------------------------------------------*/
  /* Increase the maxBuffer to 10MB for commands */
  /* with a lot of output. This is not necessary */
  /* with spawn but it has other issues.         */
  /*---------------------------------------------*/
  exec(cmd, { maxBuffer: 1000*1024 }, function(err, stdout)
    {
    if      (!err)                   cb(stdout);
    else if (err.code | 0 == -4082) run(cmd, cb);
    else throw err;
    });
  };

/*******************************************************************************
* runCommand */
/**
* Logs the command and calls <c>run</c>.
*******************************************************************************/
var runCommand = function(cmd, cb)
  {
  console.log(cmd);
  run(cmd, cb);
  }

/*******************************************************************************
* Main line
*******************************************************************************/
var doLinks  = (process.argv[2] || "").toLowerCase() == 'links';
var names    = Object.keys(packages);
var name;
var installed;
var links;

/*------------------------------------------*/
/* Get the list of installed packages for   */
/* version comparison and install packages. */
/*------------------------------------------*/
console.log('Configuring global Node environment...')
run('npm ls -g --json', function(stdout)
  {
  installed = JSON.parse(stdout).dependencies || {};
  doWhile();
  });

/*--------------------------------------------*/
/* Start of asynchronous package installation */
/* loop. Do until all packages installed.     */
/*--------------------------------------------*/
var doWhile = function()
  {
  if (name = names.shift())
    doWhile0();
  }

var doWhile0 = function()
  {
  /*----------------------------------------------*/
  /* Installed package specification comes from   */
  /* 'from' field of installed packages. Required */
  /* specification comes from the packages list.  */
  /*----------------------------------------------*/
  var current  = (installed[name] || {}).from;
  var required =   packages[name];

  /*---------------------------------------*/
  /* Install the package if not installed. */
  /*---------------------------------------*/
  if (!current)
    runCommand('npm install -g '+required, doWhile1);

  /*------------------------------------*/
  /* If the installed version does not  */
  /* match, uninstall and then install. */
  /*------------------------------------*/
  else if (current != required)
    {
    delete installed[name];
    runCommand('npm remove -g '+name, function() 
      {
      runCommand('npm remove '+name, doWhile0);
      });
    }

  /*------------------------------------*/
  /* Skip package if already installed. */
  /*------------------------------------*/
  else
    doWhile1();
  };

var doWhile1 = function()
  {
  /*-------------------------------------------------------*/
  /* Create link to global package from local environment. */
  /*-------------------------------------------------------*/
  if (doLinks && !fs.existsSync(path.join('node_modules', name)))
    runCommand('npm link '+name, doWhile);
  else
    doWhile();
  };

Bây giờ nếu tôi muốn cập nhật một công cụ toàn cầu cho các nhà phát triển của mình, tôi sẽ cập nhật đối tượng "gói" và kiểm tra tập lệnh mới. Các nhà phát triển của tôi kiểm tra nó và chạy nó với "nút npm-setup.js" hoặc bằng "npm install" từ bất kỳ sản phẩm nào đang được phát triển để cập nhật môi trường toàn cầu. Toàn bộ điều mất 5 phút.

Ngoài ra, để định cấu hình môi trường cho nhà phát triển mới, trước tiên họ phải cài đặt NodeJS và GIT cho Windows, khởi động lại máy tính của họ, kiểm tra thư mục "Tệp chung" và bất kỳ sản phẩm nào đang được phát triển và bắt đầu hoạt động.

"Gói.json" cho sản phẩm .NET gọi tập lệnh này trước khi cài đặt:

{ 
"name"                    : "Books",
"description"             : "Node (npm) configuration for Books Database Web Application Tools",
"version"                 : "2.1.1",
"private"                 : true,
"scripts":
  {
  "preinstall"            : "node ../../SharedFiles/npm-setup.js links",
  "postinstall"           : "bower install"
  },
"dependencies": {}
}

Ghi chú

  • Lưu ý tham chiếu tập lệnh yêu cầu dấu gạch chéo về phía trước ngay cả trong môi trường Windows.

  • "npm ls" sẽ cung cấp các thông báo "npm ERR! ngoại lai:" cho tất cả các gói được liên kết cục bộ vì chúng không được liệt kê trong "phụ thuộc" "gói.json".

Chỉnh sửa 1/29/16

npm-setup.jsKịch bản cập nhật ở trên đã được sửa đổi như sau:

  • Gói "phiên bản" var packageshiện là giá trị "gói" được truyền npm installvào dòng lệnh. Điều này đã được thay đổi để cho phép cài đặt các gói từ một nơi khác ngoài kho lưu trữ đã đăng ký.

  • Nếu gói đã được cài đặt nhưng không phải là gói được yêu cầu, gói hiện có sẽ bị xóa và gói chính xác được cài đặt.

  • Vì những lý do không rõ, npm sẽ định kỳ đưa ra lỗi EBUSY (-4082) khi thực hiện cài đặt hoặc liên kết. Lỗi này bị mắc kẹt và lệnh được thực thi lại. Lỗi hiếm khi xảy ra lần thứ hai và dường như luôn luôn rõ ràng.


Đây là một phao cứu sinh @ sthames42! Tôi đã bị troll hàng giờ để cố gắng tìm ra chính xác làm thế nào để làm điều này. Rõ ràng, toàn diện, nói chung là tuyệt vời. #point Câu hỏi: (a) Tại sao Bower trong cài đặt bài đăng khi nó đã có trong danh sách gói? (b) Làm thế nào để KHÔNG liên kết cục bộ các gói toàn cầu? Chỉ không bao gồm "liên kết" trong lệnh?
MaxRocket

@MaxRocket: Vui mừng tôi có thể giúp. Tôi đã cập nhật câu trả lời để bao gồm mới nhất của tôi hoạt động tốt hơn nhiều. Trả lời: (a) lệnh 'bower install' chạy sau khi 'npm install' được thực hiện để cài đặt các thành phần Bower được liệt kê trong tệp bower.json không được hiển thị ở đây. Tôi muốn người của tôi có thể gõ 'npm install' và môi trường của họ được thiết lập đầy đủ mà không phải gõ một lệnh khác. (b) Có.
sthames42

Phiên bản hiện tại của kịch bản này hiện đang được duy trì ở đây .
sthames42

6

Bạn có thể sử dụng một tệp riêng, như npm_globals.txt, thay vì package.json. Tệp này sẽ chứa mỗi mô-đun trên một dòng mới như thế này,

mongoose@1.4.0
node.io@0.3.3
jquery@1.5.1
jsdom@0.2.0
cron@0.1.2

Sau đó, trong dòng lệnh chạy,

< npm_globals.txt xargs npm install -g

Kiểm tra xem họ đã cài đặt đúng chưa,

npm list -g --depth=0

Về việc bạn có nên làm điều này hay không, tôi nghĩ tất cả phụ thuộc vào trường hợp sử dụng. Đối với hầu hết các dự án, điều này là không cần thiết; và có dự án của bạn package.jsongói gọn các công cụ và phụ thuộc này với nhau được ưu tiên hơn nhiều.

Nhưng ngày nay tôi thấy rằng tôi luôn cài đặt create-react-appvà các CLI khác trên toàn cầu khi tôi nhảy lên một máy mới. Thật tuyệt khi có một cách dễ dàng để cài đặt một công cụ toàn cầu và các phụ thuộc của nó khi phiên bản không quan trọng lắm.

Và ngày nay, tôi đang sử dụng npx, một người chạy gói npm , thay vì cài đặt các gói trên toàn cầu.


3

Tất cả các mô-đun từ pack.json được cài đặt vào ./node_modules/

Tôi không thể tìm thấy điều này được nêu rõ ràng nhưng đây là tài liệu tham khảo pack.json cho NPM .


1

Xây dựng kịch bản của riêng bạn để cài đặt các phụ thuộc toàn cầu. Nó không mất nhiều. pack.json khá mở rộng.

const {execSync} = require('child_process');

JSON.parse(fs.readFileSync('package.json'))
     .globalDependencies.foreach(
         globaldep => execSync('npm i -g ' + globaldep)
     );

Sử dụng ở trên, bạn thậm chí có thể làm cho nó nội tuyến, bên dưới!

Nhìn vào cài đặt sẵn bên dưới:

{
  "name": "Project Name",
  "version": "0.1.0",
  "description": "Project Description",
  "main": "app.js",
  "scripts": {
    "preinstall": "node -e \"const {execSync} = require('child_process'); JSON.parse(fs.readFileSync('package.json')).globalDependencies.foreach(globaldep => execSync('npm i -g ' + globaldep));\"",
    "build": "your transpile/compile script",
    "start": "node app.js",
    "test": "./node_modules/.bin/mocha --reporter spec",
    "patch-release": "npm version patch && npm publish && git add . && git commit -m \"auto-commit\" && git push --follow-tags"
  },
  "dependencies": [
  },
  "globalDependencies": [
    "cordova@8.1.2",
    "ionic",
    "potato"
  ],
  "author": "author",
  "license": "MIT",
  "devDependencies": {
    "chai": "^4.2.0",
    "mocha": "^5.2.0"
  },
  "bin": {
    "app": "app.js"
  }
}

Các tác giả của nút có thể không thừa nhận gói.json là một tệp dự án. Nhưng nó là.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.