nodebook
Version:
Node.js • Apprendre par la pratique. Familiarisez-vous avec JavaScript, Node.js et l'écosystème de modules npm. Apprenez à concevoir et à déployer des *applications web* et des *outils en ligne de commande*.
1,572 lines (1,500 loc) • 163 kB
HTML
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="generator" content="Asciidoctor 2.0.9">
<title>Jouer avec npm</title>
<style>
#header,
#content,
#footer {
margin: 2rem auto;
max-width: 46rem;
}
#header {
margin-top: 0;
}
.title,
#toctitle {
color: var(--dark-accent);
}
a {
/* white-space: nowrap; */
}
img, iframe, video, audio {
max-width: 100%;
}
p {
font-weight: normal;
}
/* Taken out from book.css */
dl dt {
margin-bottom: 0.3125em;
font-weight: bold;
}
dl dd {
margin-bottom: 1.25em;
}
dt,
th.tableblock,
td.content,
div.footnote {
text-rendering: optimizeLegibility;
}
.literalblock pre,
.literalblock pre[class],
.listingblock pre,
.listingblock pre[class] {
overflow: auto;
word-wrap: break-word;
}
.literalblock pre.nowrap,
.literalblock pre[class].nowrap,
.listingblock pre.nowrap,
.listingblock pre[class].nowrap {
overflow-x: auto;
white-space: pre;
word-wrap: normal;
}
.listingblock {
margin: 0 0 2em;
}
.listingblock > .content {
position: relative;
}
.listingblock > .title {
font-weight: bold;
}
.listingblock code[data-lang]::before {
display: none;
content: attr(data-lang);
position: absolute;
font-size: 0.75em;
top: 1em;
right: 1em;
line-height: 1;
text-transform: uppercase;
color: #999;
}
.listingblock:hover code[data-lang]::before {
display: block;
}
.listingblock.terminal pre .command::before {
content: attr(data-prompt);
padding-right: 0.5em;
color: #999;
}
td.hdlist1,
td.hdlist2 {
vertical-align: top;
padding-right: 0.625em;
}
td.hdlist1 {
font-weight: bold;
}
.literalblock + .colist,
.listingblock + .colist {
margin-top: -1.5em;
}
.colist td:not([class]):first-child {
padding: 0.4em 0.75em 0 0.75em;
line-height: 1;
vertical-align: top;
}
.colist td:not([class]):first-child img {
max-width: none;
}
.colist td:not([class]):last-child {
padding: 0.25em 0;
}
/* Custom classes */
.line-through {
text-decoration: line-through;
}
.RemarquePreTitre,
#toctitle {
font-style: normal;
font-weight: bold;
}
.RemarquePreTitre::after {
content: "•";
padding-left: 5px;
}
.admonitionblock {
}
.admonitionblock > table,
.exampleblock {
--commented: rgba(17, 17, 68, .65);
--border-radius-base: 8px;
background-color: #fafafa;
border: 1px solid var(--dark-shade);
border-left: none;
border-right: none;
margin: 1.5em 0;
padding: 1em;
}
.exampleblock .title {
font-weight: bold;
}
.icon .title {
font-size: 2em;
}
.admonitionblock > table td.icon {
display: none;
vertical-align: middle;
}
@media screen and (min-width: 769px) {
.admonitionblock > table td.icon {
display: table-cell;
}
}
.admonitionblock > table td.icon {
padding-right: 1em;
}
.admonitionblock > table td.icon img {
max-width: none;
}
.colist ol {
margin-left: 1.5em; /* aligns with the listing edge */
padding-left: 0;
font-weight: bold; /* makes it stand out more */
}
.colist ol p {
margin: 0 0 .5em;
}
.listingblock:not(.prismjs) pre,
.language-bash.hljs {
background: #323232;
color: wheat;
margin: 0;
padding: 1rem;
}
.language-bash.hljs .hljs-built_in,
.language-bash.hljs .hljs-builtin-name {
color: white;
}
.language-bash.hljs .hljs-string {
color: lightgreen;
}
.language-bash.hljs .hljs-variable {
color: lightskyblue;
}
.keyseq {
font-weight: normal;
white-space: nowrap;
}
.language-bash.hljs .keyseq {
color: white;
}
.language-bash.hljs kbd {
background: transparent;
box-shadow: none;
color: white;
font-size: 0.8em;
font-weight: bold;
padding: 0.1em 0.4em;
}
.listingblock pre.highlightjs,
.listingblock pre.prismjs {
background-color: transparent;
margin: 0;
padding: 0;
}
.listingblock pre.highlightjs > code,
.listingblock pre.prismjs {
border-left: 4px solid var(--dark-accent);
padding-left: 1em;
font-size: .8em;
}
.listingblock pre.highlightjs > code.language-bash {
border-left-color: limegreen;
}
.token.comment .conum {
font-weight: normal;
}
.hdlist .hdlist1 {
text-align: right;
white-space: nowrap;
}
td > p:first-child {
margin-top: 0;
}
.hljs-comment {
font-style: normal !important;
}
#toc.toc2 a {
text-decoration: none;
white-space: normal;
}
#toc.toc2 a:hover,
#toc.toc2 a:focus {
text-decoration: underline;
}
#toc.toc2 ul {
list-style: none;
}
#toc.toc2 > ul {
padding-left: 0;
}
#toc.toc2 ul ul {
padding-left: 1em;
}
@media screen and (min-width: 769px) {
body {
padding-left: 25vw !important;
}
#header,
#content,
#footer {
margin-left: 0;
}
#toc.toc2 {
height: 100%;
left: 0;
max-width: 20vw;
overflow: auto;
padding: 1rem;
position: fixed;
top: 0;
z-index: 1000;
}
#toc.toc2 > ul {
font-size: 0.85em;
}
#toc li.active > a[href^="#"],
[id]:target {
background: #ffc;
}
}
.admonitionblock.context-callout > table {
border-width: 5px;
border-color: var(--brand-color);
}
</style>
<style type="text/css" class="prism-theme">/**
* prism.js default theme for JavaScript, CSS and HTML
* Based on dabblet (http://dabblet.com)
* @author Lea Verou
*/
code[class*="language-"],
pre[class*="language-"] {
color: black;
background: none;
text-shadow: 0 1px white;
font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
font-size: 1em;
text-align: left;
white-space: pre;
word-spacing: normal;
word-break: normal;
word-wrap: normal;
line-height: 1.5;
-moz-tab-size: 4;
-o-tab-size: 4;
tab-size: 4;
-webkit-hyphens: none;
-moz-hyphens: none;
-ms-hyphens: none;
hyphens: none;
}
pre[class*="language-"]::-moz-selection, pre[class*="language-"] ::-moz-selection,
code[class*="language-"]::-moz-selection, code[class*="language-"] ::-moz-selection {
text-shadow: none;
background: #b3d4fc;
}
pre[class*="language-"]::selection, pre[class*="language-"] ::selection,
code[class*="language-"]::selection, code[class*="language-"] ::selection {
text-shadow: none;
background: #b3d4fc;
}
@media print {
code[class*="language-"],
pre[class*="language-"] {
text-shadow: none;
}
}
/* Code blocks */
pre[class*="language-"] {
padding: 1em;
margin: .5em 0;
overflow: auto;
}
:not(pre) > code[class*="language-"],
pre[class*="language-"] {
background: #f5f2f0;
}
/* Inline code */
:not(pre) > code[class*="language-"] {
padding: .1em;
border-radius: .3em;
white-space: normal;
}
.token.comment,
.token.prolog,
.token.doctype,
.token.cdata {
color: slategray;
}
.token.punctuation {
color: #999;
}
.namespace {
opacity: .7;
}
.token.property,
.token.tag,
.token.boolean,
.token.number,
.token.constant,
.token.symbol,
.token.deleted {
color: #905;
}
.token.selector,
.token.attr-name,
.token.string,
.token.char,
.token.builtin,
.token.inserted {
color: #690;
}
.token.operator,
.token.entity,
.token.url,
.language-css .token.string,
.style .token.string {
color: #9a6e3a;
background: hsla(0, 0%, 100%, .5);
}
.token.atrule,
.token.attr-value,
.token.keyword {
color: #07a;
}
.token.function,
.token.class-name {
color: #DD4A68;
}
.token.regex,
.token.important,
.token.variable {
color: #e90;
}
.token.important,
.token.bold {
font-weight: bold;
}
.token.italic {
font-style: italic;
}
.token.entity {
cursor: help;
}
</style>
<link rel="stylesheet" href="https://oncletom.io/styles/blog.css?v=v3.3.2">
<!-- WebMentions -->
<link rel="pingback" href="https://webmention.io/oncletom.io/xmlrpc">
<link rel="webmention" href="https://webmention.io/oncletom.io/webmention">
<!-- Open Graph -->
<meta property="og:type" content="book">
<meta property="og:image" content="https://oncletom.io/images/publications/nodejs-cover.png">
<meta property="og:book:author" content="Thomas Parisot">
<meta property="og:book:isbn" content="978-2212139938">
<meta property="og:book:release_date" content="2018-12-06">
<meta property="og:book:tag" content="Node.js">
<meta property="og:book:tag" content="JavaScript">
<meta property="og:book:tag" content="npm">
<meta property="og:book:tag" content="Développement front-end">
<meta property="og:book:tag" content="Développement back-end">
<meta property="og:locale" content="fr_FR">
<meta property="og:site_name" content="Node.js • Apprendre par la pratique">
<!-- Twitter OpenGraph -->
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:site" content="@oncletom">
<meta name="twitter:creator" content="@oncletom">
<style type="text/css" class="extension-interactive-runner">[data-interactive-runtime="loaded"] .interactive--javascript code[data-lang]:before {
background-color: #fcfcfc;
border: 1px solid #0c2;
border-radius: 1px;
color: #0c2;
cursor: pointer;
display: inline-block;
font-weight: bold;
padding: .5em 1em;
top: -2em;
}
[lang="en"] [data-interactive-runtime="loaded"] .interactive--javascript code[data-lang]:before {
content: "▶ run code";
}
[lang="fr"] [data-interactive-runtime="loaded"] .interactive--javascript code[data-lang]:before {
content: "▶ voir le résultat";
}
.interactive--javascript code[data-label]:before {
content: attr(data-label);
}
.interactive iframe {
position: absolute;
visibility: hidden;
}
.interactive.status--loaded iframe {
position: inherit;
visibility: visible;
}
.interactive.status--loading {
opacity: .5;
}
</style>
<script class="extension-interactive-runner">
(function(d){
document.addEventListener('DOMContentLoaded', function(){
const script = d.createElement('script');
script.src = 'https://embed.runkit.com/';
script.async = true;
script.onload = function(){
function makeListingInteractive (element){
if (element.classList.contains('interactive--installed') || element.classList.contains('status--loading')) {
return;
}
const code = element.querySelector('code');
const nodeVersion = /interactive--runtime--node-([^\s]+)/.exec(element.className)[1];
const isEndpoint = element.classList.contains('interactive--endpoint');
const mode = isEndpoint ? 'endpoint' : null;
let preamble = '';
const source = code
.textContent
.replace(/\/\/\s*\(\d+\)$/gm, '')
.replace(/^["']?use strict["'][; ]*\n/, '');
if (isEndpoint) {
preamble = `process.nextTick(() => {
if (typeof module.exports === 'function') {
exports.endpoint = module.exports;
}
else if (typeof server !== 'undefined') {
exports.endpoint = server.listeners("request").pop();
}
});`
}
element.classList.add('status--loading');
// eslint-disable-next-line no-undef
RunKit.createNotebook({
nodeVersion,
element,
source,
mode,
preamble,
onLoad: function(ntbk) {
element.classList.add('interactive--installed');
element.classList.remove('status--loading');
element.classList.add('status--loaded');
code.parentNode.setAttribute('hidden', true);
ntbk.evaluate();
}
});
}
function installEvents () {
function getParent(el, condition) {
let parent = el;
while(parent = parent.parentNode) {
if (condition(parent)) {
return parent;
}
}
}
function hasClass(className) {
return function check(el) {
return el.classList.contains(className);
}
}
document.querySelector('body').addEventListener('click', function(el) {
if (el.target.classList.contains('language-javascript') || el.target.classList.contains('language-js')) {
const parentNode = getParent(
el.target,
hasClass('interactive--javascript')
);
makeListingInteractive(parentNode);
}
});
}
installEvents();
document.body.dataset.interactiveRuntime = 'loaded';
};
document.body.appendChild(script);
});
})(document);</script>
<style type="text/css">
.listingblock [data-bash-subs]::before {
content: attr(data-bash-subs) " ";
opacity: .5; }
.listingblock [data-bash-conum]::before {
content: "(" attr(data-bash-conum) ")";
font-weight: bold;
opacity: .7;
}</style>
<script>
(function(d){
d.addEventListener('DOMContentLoaded', function(){
const {origin} = window.location;
Array.from(document.querySelectorAll('a[href]'))
.filter(link => link.href.indexOf(origin) !== 0)
.forEach(link => {
link.setAttribute('target', '_blank');
link.setAttribute('rel', 'noopener');
});
});
})(document);</script>
<script>
(function(d){
d.addEventListener('DOMContentLoaded', function(){
const script = d.createElement('script');
script.src = 'https://unpkg.com/menuspy@1.3.0/dist/menuspy.js';
script.async = true;
script.onload = () => new MenuSpy(document.querySelector('#toc'), {enableLocationHash: false});
d.body.appendChild(script);
});
})(document);</script>
<style type="text/css">
#toc li.active > a[href^="#"] {
font-weight: bold;
}
#toc li.active > a[href^="#"]::before {
content: "▶ ";
display: inline-block;
position: absolute;
margin-left: -1.2em;
font-size: .8em;
margin-top: 3px;
}
</style>
</head>
<body class="book toc2 toc-left">
<div id="header">
<h1>Jouer avec npm</h1>
<div id="toc" class="toc2">
<div id="toctitle">Table des matières</div>
<ul class="sectlevel1">
<li><a href="#cli">1. Créer un fichier <code>package.json</code></a></li>
<li><a href="#modules">2. Installer des modules npm</a>
<ul class="sectlevel2">
<li><a href="#depuis_le_registre_npm">2.1. Depuis le registre npm</a></li>
<li><a href="#registry">2.2. Trouver son bonheur dans le registre npm</a></li>
<li><a href="#uninstall">2.3. Désinstaller un module</a></li>
<li><a href="#install">2.4. Depuis un fichier <code>package.json</code></a></li>
<li><a href="#install.version">2.5. Spécifier une version</a></li>
<li><a href="#semver">2.6. Comprendre les numéros de versions (Semantic Versioning)</a></li>
<li><a href="#update">2.7. Mises à jour</a></li>
</ul>
</li>
<li><a href="#autres_manières_dinstaller_et_dutiliser_des_modulesnpm">3. Autres manières d’installer et d’utiliser des modules npm</a>
<ul class="sectlevel2">
<li><a href="#install.git">3.1. Depuis GitHub, GitLab ou un dépôt Git</a></li>
<li><a href="#install.dev">3.2. Dépendances de développement</a></li>
<li><a href="#install.global">3.3. Exécutable système (installation globale)</a></li>
</ul>
</li>
<li><a href="#scripts">4. Outiller un projet avec les scripts npm</a>
<ul class="sectlevel2">
<li><a href="#start">4.1. Démarrer l’application</a></li>
<li><a href="#test">4.2. Exécuter des tests</a></li>
<li><a href="#run">4.3. Créer un script npm personnalisé</a></li>
<li><a href="#run-pre-post">4.4. Exécuter des commandes avant et après des scripts npm</a></li>
<li><a href="#run-all">4.5. Automatiser tout l’outillage projet</a></li>
</ul>
</li>
<li><a href="#package.json">5. Anatomie du fichier <code>package.json</code></a></li>
<li><a href="#commands">6. Quelques commandes pour aller plus loin</a>
<ul class="sectlevel2">
<li><a href="#view">6.1. npm view : voir les informations d’un module</a></li>
<li><a href="#npx">6.2. npx : exécuter un module sans l’installer</a></li>
<li><a href="#home">6.3. npm home : visiter le site web d’un module</a></li>
<li><a href="#audit">6.4. npm audit : vérifier la sécurité des dépendances</a></li>
<li><a href="#ci">6.5. npm clean-install : installer à toute vitesse</a></li>
<li><a href="#doctor">6.6. npm doctor : vérifier l’état du système</a></li>
<li><a href="#config">6.7. npm config : changer les réglages de l’exécutable <code>npm</code></a></li>
<li><a href="#publish">6.8. npm publish : publier un module npm</a></li>
<li><a href="#version">6.9. npm version : déterminer une nouvelle version sans se tromper</a></li>
</ul>
</li>
<li><a href="#questions">7. Questions et mystères autour de npm</a>
<ul class="sectlevel2">
<li><a href="#npm.update">7.1. Quand mettre à jour l’exécutable npm ?</a></li>
<li><a href="#package-lock">7.2. Je ne vois pas l’intérêt du fichier package-lock.json</a></li>
<li><a href="#bower">7.3. npm c’est pour le back-end et bower pour le front-end</a></li>
<li><a href="#est_ce_que_je_dois_versionner_le_répertoire_node_modules">7.4. Est-ce que je dois versionner le répertoire node_modules ?</a></li>
<li><a href="#yarn">7.5. Il paraît que Yarn, c’est mieux</a></li>
<li><a href="#all-your-base-are-belong-to-us">7.6. npm est lent, il installe la moitié d’Internet à chaque fois</a></li>
<li><a href="#errors">7.7. Que signifient les erreurs affichées pendant npm install ?</a>
<ul class="sectlevel3">
<li><a href="#error-deprecated">7.7.1. Module déprécié</a></li>
<li><a href="#error-skipping">7.7.2. Problème avec une dépendance optionnelle</a></li>
<li><a href="#error-404">7.7.3. Module introuvable</a></li>
<li><a href="#error-crlf">7.7.4. Caractère de fin de ligne sous Windows</a></li>
<li><a href="#error-pkg">7.7.5. Fichier package.json incomplet</a></li>
<li><a href="#error-peer-dependency">7.7.6. Dépendance complémentaire à installer</a></li>
</ul>
</li>
</ul>
</li>
<li><a href="#conclusion">8. Conclusion</a></li>
</ul>
</div>
</div>
<div id="content">
<div id="preamble">
<div class="sectionbody">
<div class="admonitionblock tip context-callout">
<table>
<tr>
<td class="icon">
<div class="title">💡</div>
</td>
<td class="content">
<div class="paragraph">
<p>Vous êtes en train de lire
le Chapitre 5
du <a href="https://oncletom.io/node.js/">livre “Node.js”</a>, écrit par
<a href="https://oncletom.io">Thomas Parisot</a> et publié aux
<a href="https://editions-eyrolles.com/Livre/9782212139938">Éditions Eyrolles</a>.</p>
</div>
<div class="paragraph">
<p>L’ouvrage vous plaît ? Achetez-le sur <a href="https://amzn.to/2E58PEw">Amazon.fr</a> ou en
<a href="https://www.placedeslibraires.fr/livre/9782212139938">librairie</a>.
<a href="https://opencollective.com/nodebook">Donnez quelques euros</a> pour contribuer
à sa gratuité en ligne.</p>
</div>
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>Savoir naviguer dans la richesse de l’écosystème <code>npm</code> est une force pour
la durabilité de nos projets.
Ces modules nous aident à façonner un outillage résilient et adapté à chacun
de nos projets.</p>
</div>
<div class="exampleblock">
<div class="content">
<div class="ulist">
<div class="title">Sommaire</div>
<ul>
<li>
<p>Créer un fichier <code>package.json</code></p>
</li>
<li>
<p>Installer un module <code>npm</code></p>
</li>
<li>
<p>Outiller un projet avec les scripts <code>npm</code></p>
</li>
<li>
<p>Anatomie du fichier <code>package.json</code></p>
</li>
<li>
<p>Quelques commandes pour aller plus loin</p>
</li>
<li>
<p>Questions et mystères autour de <code>npm</code></p>
</li>
</ul>
</div>
</div>
</div>
<div class="quoteblock abstract">
<blockquote>
<div class="paragraph">
<p>Ce chapitre va nous permettre d’y voir plus clair du côté des <a href="#modules">modules <code>npm</code></a>.
Nous apprendrons comment identifier des modules de confiance, les installer et
les mettre à jour sans casser nos projets.</p>
</div>
<div class="paragraph">
<p>Nous nous tournerons ensuite du côté des <a href="#scripts">scripts <code>npm</code></a> pour créer
un outillage sur mesure et de qualité.
Grâce à eux, nous serons en mesure d’automatiser les tâches répétitives à notre
rythme.</p>
</div>
<div class="paragraph">
<p>Enfin, nous découvrirons des commandes moins connues de <code>npm</code>.
Elles pourrons nous faciliter la vie ou nous débloquer quand ça ne va pas.</p>
</div>
</blockquote>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<div class="title">💬</div>
</td>
<td class="content">
<div class="title"><span class="RemarquePreTitre">Remarque</span> Versions de Node et npm</div>
<div class="paragraph">
<p>Le contenu de ce chapitre utilise les versions <strong>Node v10</strong>
et <strong>npm v6</strong>.
Ce sont les versions stables recommandées en 2019.</p>
</div>
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>Le mot <em>npm</em> correspond à trois concepts différents que nous aborderons
tout au long de ce chapitre :</p>
</div>
<div class="ulist">
<ul>
<li>
<p>l'<strong>exécutable</strong> <code>npm</code> – un programme écrit en ECMAScript ;</p>
</li>
<li>
<p>le <strong>registre</strong> <code>npm</code> – une plate-forme de distribution de modules ;</p>
</li>
<li>
<p>un <strong>module</strong> <code>npm</code> – en général installé depuis le registre et utilisable
avec les fonctions <code>require()</code> et <code>import</code>.</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>Je préciserai toujours si l’utilisation de <code>npm</code> fait référence
à l'<em>exécutable</em>, au <em>registre</em> ou à un <em>module</em>.</p>
</div>
<div class="paragraph">
<p>L’exécutable <code>npm</code> est installé par défaut avec Node.
Vérifions la version installée en ouvrant un terminal
et en écrivant la commande suivante :</p>
</div>
<div class="listingblock">
<div class="content">
<pre><span data-bash-subs="$"></span>npm --version
6.4.0</pre>
</div>
</div>
<div class="paragraph">
<p>Si un message s’affiche en indiquant que <code>npm</code> n’est pas un programme reconnu,
veuillez vous référer au <a href="../chapter-02/index.html">chapitre 2</a> et
vérifier que Node v10 est bien installé.</p>
</div>
<div class="admonitionblock tip">
<table>
<tr>
<td class="icon">
<div class="title">💡</div>
</td>
<td class="content">
<div class="title"><span class="RemarquePreTitre">Pratique</span> Jouer avec les exemples dans un terminal</div>
<div class="paragraph">
<p>Les exemples titrés d’un nom de fichier peuvent être installés sur votre ordinateur.
Exécutez-les dans un terminal et amusez-vous à les modifier en parallèle de
votre lecture pour voir ce qui change.</p>
</div>
<div class="listingblock">
<div class="title">Installation des exemples via le module npm <code>nodebook</code></div>
<div class="content">
<pre><span data-bash-subs="$"></span>npm install --global nodebook
<span data-bash-subs="$"></span>nodebook install chapter-05
<span data-bash-subs="$"></span>cd $(nodebook dir chapter-05)</pre>
</div>
</div>
<div class="paragraph">
<p>La commande suivante devrait afficher un résultat qui confirme que vous êtes
au bon endroit :</p>
</div>
<div class="listingblock">
<div class="content">
<pre><span data-bash-subs="$"></span>node hello.js</pre>
</div>
</div>
<div class="paragraph">
<p>Suivez à nouveau les instructions d’installation pour rétablir les exemples
dans leur état initial.</p>
</div>
</td>
</tr>
</table>
</div>
</div>
</div>
<div class="sect1">
<h2 id="cli">1. Créer un fichier <code>package.json</code></h2>
<div class="sectionbody">
<div class="paragraph">
<p>
</p>
</div>
<div class="paragraph">
<p>La présence d’un fichier <code>package.json</code> devient nécessaire dès qu’un projet
inclut un <a href="#modules">module <code>npm</code></a> ou a vocation à être publié pour être repris
dans un autre projet – que ce soit dans un cadre professionnel ou personnel.</p>
</div>
<div class="paragraph">
<p>Le fichier <code>package.json</code> est la clé de voûte servant à reproduire l’installation
du projet et créer un <a href="#scripts">outillage autonome</a>.
La commande <code>npm init</code> génère un tel fichier.
L’utilisation de l’option <code>--yes</code> va plus vite car elle nous évite
de répondre aux questions :</p>
</div>
<div class="listingblock">
<div class="content">
<pre><span data-bash-subs="$"></span>npm init --yes</pre>
</div>
</div>
<div class="paragraph">
<p>Si aucun fichier <code>package.json</code> n’existe dans le répertoire courant,
il sera créé avec des valeurs par défaut – le nom du module correspondra
au nom du répertoire courant.
Si ce fichier existait déjà, il sera alors préservé et son contenu sera affiché :</p>
</div>
<div class="listingblock">
<div class="title">package.json</div>
<div class="content">
<pre>{
"name": "nodebook.chapter-05",
"private": true,
"version": "1.0.0",
"main": "./examples/index.js",
"description": "",
"scripts": {
"lint": "eslint ./examples",
"print-args": "node examples/print-args.js",
"start": "micro examples/app.js",
"test": "mocha examples/tests.js",
"pretest": "npm run lint"
},
"engines": {
"node": "^10.0.0"
},
"author": "Thomas Parisot (https://oncletom.io)",
"license": "MIT",
"bugs": {
"url": "https://github.com/oncletom/nodebook/issues"
},
"homepage": "https://github.com/oncletom/nodebook",
"dependencies": {
"cowsay": "^1.3.1",
"lodash": "^4.17.11",
"micro": "^9.3.3"
},
"devDependencies": {
"eslint": "^5.9.0",
"mocha": "^5.2.0"
}
}</pre>
</div>
</div>
<div class="paragraph">
<p>Nous reviendrons sur la structure du fichier.
En attendant, focalisons-nous sur les opérations courantes comme
l’installation de modules.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="modules">2. Installer des modules npm</h2>
<div class="sectionbody">
<div class="paragraph">
<p>
</p>
</div>
<div class="paragraph">
<p>Le mécanisme des modules est documenté dans
le <a href="../chapter-04/index.html#modules">chapitre 4</a>.
Les fonctions <code>require()</code> et <code>import</code> chargent nos propres modules mais aussi
les modules de base, installés avec Node.
Les modules <code>npm</code> sont <strong>complémentaires et téléchargeables</strong> à l’aide
de l’exécutable <code>npm</code>.</p>
</div>
<div class="paragraph">
<p>Cette section va nous aider à comprendre ce qui se passe pendant les phases
d’installation, de mise à jour et de désinstallation des modules <code>npm</code>.</p>
</div>
<div class="sect2">
<h3 id="depuis_le_registre_npm">2.1. Depuis le registre npm</h3>
<div class="paragraph">
<p></p>
</div>
<div class="paragraph">
<p>Le registre <code>npm</code> (<span class="URL"><a href="https://npmjs.com" class="bare">npmjs.com</a></span>) est l’hébergement principal
des modules ECMAScript, pour Node et le front-end.</p>
</div>
<div class="paragraph">
<p>La commande <code>npm install</code> s’utilise directement quand nous connaissons déjà
le nom d’un module à installer,
par exemple <em>cowsay</em> (<span class="URL"><a href="https://npmjs.com/cowsay" class="bare">npmjs.com/cowsay</a></span>) :
</p>
</div>
<div class="listingblock">
<div class="content">
<pre><span data-bash-subs="$"></span>npm install cowsay
+ cowsay@1.3.1
added 10 packages from 3 contributors in 1.667s
found 0 vulnerabilities</pre>
</div>
</div>
<div class="paragraph">
<p>Le module est installé et prêt à être inclus dans un script.
Nous constatons aussi que le champ <code>dependencies</code> est apparu
dans le fichier <code>package.json</code> :
</p>
</div>
<div class="listingblock">
<div class="title">package.json</div>
<div class="content">
<pre class="highlight highlight-prismjs prismjs language-json"><code class="language-json" data-lang="json"><span class="token punctuation">{</span>
...
<span class="token property">"dependencies"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
<span class="token property">"cowsay"</span><span class="token operator">:</span> <span class="token string">"^1.3.1"</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>L’exécutable <code>npm</code> tient les comptes des modules installés à notre demande.
Cela nous sera utile pour <a href="#install">installer les modules sur un autre ordinateur</a>.
Nous reviendrons plus tard sur la notation des versions
– on en reparlera sous le nom de <em>versions sémantiques</em> (<em>Semantic Versionning</em>).
</p>
</div>
<div class="listingblock interactive interactive--javascript interactive--runtime--node-v10">
<div class="title">cow.js</div>
<div class="content">
<pre class="highlight highlight-prismjs prismjs language-javascript"><code class="language-javascript" data-lang="javascript"><span class="token string">'use strict'</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> <span class="token punctuation">{</span>say<span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'cowsay'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> message <span class="token operator">=</span> <span class="token function">say</span><span class="token punctuation">(</span><span class="token punctuation">{</span> text<span class="token punctuation">:</span> <span class="token string">'Bonjour !'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>message<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>L’inclusion d’un module <code>npm</code> est identique
à celle d’un <a href="../chapter-04/index.html#modules-builtin">module de base</a>.
</p>
</div>
<div class="paragraph">
<p>Regardons le résultat sans plus tarder :</p>
</div>
<div class="listingblock">
<div class="content">
<pre><span data-bash-subs="$"></span>node cow.js
___________
< Bonjour ! >
-----------
\ ^__^
\ (oo)\_______
(__)\ )\/\
||----w |</pre>
</div>
</div>
<div class="paragraph">
<p>Le module <code>npm</code> nous a permis d’utiliser du code sans avoir à le
créer, alors qu’il n’était pas fourni par la plate-forme Node.</p>
</div>
<div class="paragraph">
<p>Maintenant que nous savons installer un module <code>npm</code>, nous pouvons en chercher
d’autres et comprendre comment les utiliser.</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<div class="title">💬</div>
</td>
<td class="content">
<div class="title"><span class="RemarquePreTitre">Question</span> Où sont stockés les modules npm ?</div>
<div class="paragraph">
<p>
Les modules <code>npm</code> et leurs dépendances sont stockés dans un répertoire
<code>node_modules</code>, situé au même niveau que le fichier <code>package.json</code>.</p>
</div>
</td>
</tr>
</table>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<div class="title">💬</div>
</td>
<td class="content">
<div class="title"><span class="RemarquePreTitre">Sous le capot</span> Ce que fait l’exécutable npm pendant l’installation</div>
<div class="paragraph">
<p>
L’exécutable <code>npm</code> effectue un bon nombre d’actions lorsqu’on valide la
commande <code>npm install cowsay</code> :</p>
</div>
<div class="olist arabic">
<ol class="arabic">
<li>
<p>Il interroge le registre <span class="URL">npmjs.com</span> pour obtenir des informations sur le module demandé.</p>
</li>
<li>
<p>Il détermine que <code>1.3.1</code> est la version la plus récente.</p>
</li>
<li>
<p>Il télécharge une archive compressée (<code>.tar.gz</code>) qui contient tous les fichiers de la version <code>1.3.1</code>.</p>
</li>
<li>
<p>L’archive est décompressée dans le répertoire <code>node_modules</code>.</p>
</li>
<li>
<p>Les dépendances sont elles aussi téléchargées puis décompressées dans le répertoire <code>node_modules</code>.</p>
</li>
<li>
<p>Le module <code>cowsay</code> est inscrit dans le fichier <code>package.json</code>.</p>
</li>
</ol>
</div>
</td>
</tr>
</table>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<div class="title">💬</div>
</td>
<td class="content">
<div class="title"><span class="RemarquePreTitre">Remarque</span> Dépendances de développement</div>
<div class="paragraph">
<p>
Il existe une variante de la commande pour distinguer les dépendances
spécifiques à l’outillage du projet.
Rendez-vous dans la section “<a href="#install.dev">Dépendances de développement</a>”
pour en savoir plus.</p>
</div>
</td>
</tr>
</table>
</div>
</div>
<div class="sect2">
<h3 id="registry">2.2. Trouver son bonheur dans le registre npm</h3>
<div class="paragraph">
<p>
</p>
</div>
<div class="paragraph">
<p>Le registre <code>npm</code> (<span class="URL"><a href="https://npmjs.com" class="bare">npmjs.com</a></span>) fourmille de modules
– de simples fonctions, des bibliothèques ou des frameworks complets.
Ils couvrent un spectre d’usages très larges : accès aux bases de données,
frameworks web, outils <em>front-end</em>, utilitaires de test,
compression de données, paiement bancaire, des frameworks mobiles, etc.</p>
</div>
<div class="paragraph">
<p>Cherchons une bibliothèque pour nous connecter à une base de données MySQL ou MariaDB.
Tapez “mysql” dans le champ de recherche du registre <code>npm</code> ou saisissez
directement l’URL menant aux résultats de cette recherche
(<span class="URL"><a href="https://npmjs.com/search?q=mysql" class="bare">npmjs.com/search?q=mysql</a></span>) :</p>
</div>
<div class="imageblock">
<div class="content">
<img src="./images/npm-registry-search.png" alt="npm registry search">
</div>
<div class="title">Figure 1. Extrait des résultats d’une recherche de modules npm avec le mot-clé “mysql”</div>
</div>
<div class="paragraph">
<p>Les résultats sont triés par pertinence – un mélange entre popularité,
qualité et maintenance des projets.</p>
</div>
<div class="paragraph">
<p>Je trouve qu’il est difficile de décider uniquement en regardant la liste.
J’ai tendance à ouvrir un onglet par module pour en lire la documentation.
Prenons le cas du module <em>mysql2</em> (<span class="URL"><a href="https://npmjs.com/mysql2" class="bare">npmjs.com/mysql2</a></span>) justement :</p>
</div>
<div class="imageblock">
<div class="content">
<img src="./images/npm-package-mysql2.png" alt="npm package mysql2">
</div>
<div class="title">Figure 2. Extrait de la page consacrée au module npm mysql2</div>
</div>
<div class="paragraph">
<p>Plusieurs éléments de cette page tendent à me rassurer
et m’aident à juger de la robustesse de ce module :</p>
</div>
<div class="ulist">
<ul>
<li>
<p>les badges colorés qui affichent le statut d’exécution des tests ;</p>
</li>
<li>
<p>une introduction de <strong>documentation claire et concise</strong> ;</p>
</li>
<li>
<p>un <strong>nombre de téléchargements</strong> en progrès réguliers ;</p>
</li>
<li>
<p>l’utilisation avec des <a href="../chapter-03/index.html#promise">promesses</a> ;</p>
</li>
<li>
<p>le nombre important de modules dépendants ;</p>
</li>
<li>
<p><strong>je reconnais une personne</strong> qui contribue du code de qualité – Rebecca Turner (<span class="URL"><a href="https://npmjs.com/~iarna" class="bare">npmjs.com/~iarna</a></span>).</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>J’ai un doute quand je lis <span class="Menu">108 issues</span> et <span class="Menu">13 pull requests</span>.
Dans ce cas-là, je me dis que les personnes qui maintiennent le projet ne sont
pas forcément très réactives.</p>
</div>
<div class="paragraph">
<p>Cependant, il y a suffisamment d’indicateurs au vert pour l’installer avec
<code>npm install mysql2</code> puis l’essayer dans un script.
</p>
</div>
<div class="paragraph">
<p>Le module <em>mysql-libmysqlclient</em> (<span class="URL"><a href="https://npmjs.com/mysql-libmysqlclient" class="bare">npmjs.com/mysql-libmysqlclient</a></span>)
ne me fait pas du tout le même effet.</p>
</div>
<div class="imageblock">
<div class="content">
<img src="./images/npm-package-mysql-libmysqlclient.png" alt="npm package mysql libmysqlclient">
</div>
<div class="title">Figure 3. Extrait de la page consacrée au module npm mysql-libmysqlclient</div>
</div>
<div class="paragraph">
<p>La page du module ne met pas d’exemple simple à comprendre et fait référence
à des versions de Node antédiluviennes.
Rien n’indique qu’il ne peut pas fonctionner avec Node v10,
mais la présence du mot <span class="Menu">binding</span> m’évoque que l’installation du module
compile un programme écrit dans un autre langage
– en l’occurrence, <em>libmysqlclient</em>.
</p>
</div>
<div class="paragraph">
<p>Point positif : il n’y a que <span class="Menu">14 issues</span> GitHub.
C’est peu, mais l’une d’entre elles est intitulée
<span class="Menu">Does not work with any modern version of Node.js</span>.
Cela confirme mes doutes ; c’est suffisant pour que je passe mon chemin.</p>
</div>
<div class="paragraph">
<p>En continuant plus loin dans la liste des résultats de recherche,
je suis tombé sur le module nommé <em>falchion</em>.</p>
</div>
<div class="imageblock">
<div class="content">
<img src="./images/npm-package-falchion.png" alt="npm package falchion">
</div>
<div class="title">Figure 4. Extrait de la page consacrée au module npm falchion</div>
</div>
<div class="paragraph">
<p>Il n’y a qu’une seule version du module, qui date de quatre années
avec une documentation qui tient sur une ligne.
Il y a très peu de chances que nous puissions en faire quelque chose.</p>
</div>
<div class="paragraph">
<p>Voici au final ce que j’estime être le plus important pour me faire
une idée d’un module et décider de l’installer ou non :
</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Présence d’une <strong>documentation</strong> – je peux me faire une idée des fonctionnalités
et de la complexité d’utilisation du module.</p>
</li>
<li>
<p>Des badges d'<strong>intégration continue</strong> – je sais ainsi qu’il y a des tests
unitaires qui sont exécutés automatiquement avant que le module soit publié.</p>
</li>
<li>
<p>Le nombre de <strong>téléchargements</strong> – je sais si d’autres personnes s’en servent
en espérant qu’ils remontent les problèmes rencontrés.</p>
</li>
<li>
<p>Le nombre de <strong>versions</strong> – cela me donne une idée de la maturité du projet
et de la réactivité aux demandes de la communauté.</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>Ce sont des <strong>critères subjectifs</strong>.
Un module est parfois populaire par ancienneté alors qu’il existe des alternatives,
plus légères ou plus simples d’utilisation.
C’est le cas du module <em>moment.js</em>, plus populaire que <em>date-fns</em> – que je préfère.</p>
</div>
<div class="paragraph">
<p>Il y a aussi des modules dans lesquels j’ai une confiance quasi-aveugle.
Ils sont publiés par les personnes présentes dans cette liste non exhaustive :</p>
</div>
<table class="tableblock frame-all grid-all stretch">
<caption class="title">Tableau 1. Personnes ayant écrit des modules npm à suivre</caption>
<colgroup>
<col style="width: 33.3333%;">
<col style="width: 33.3333%;">
<col style="width: 33.3334%;">
</colgroup>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="https://npmjs.com/~dougwilson" class="URL">dougwilson</a></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="https://github.com/jdalton" class="URL">jdalton</a></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="https://npmjs.com/~sindresorhus" class="URL">sindresorhus</a></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="https://npmjs.com/~feross" class="URL">feross</a></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="https://github.com/jshttp" class="URL">jshttp</a></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="https://npmjs.com/~substack" class="URL">substack</a></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="https://npmjs.com/~fgribreau" class="URL">fgribreau</a></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="https://npmjs.com/~mbostock" class="URL">mbostock</a></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="https://npmjs.com/~zkat" class="URL">zkat</a></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="https://npmjs.com/~iarna" class="URL">iarna</a></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="https://github.com/nodejitsu" class="URL">nodejitsu</a></p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="https://npmjs.com/~isaacs" class="URL">isaacs</a></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="https://npmjs.com/~rwaldron" class="URL">rwaldron</a></p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
</tbody>
</table>
<div class="admonitionblock tip">
<table>
<tr>
<td class="icon">
<div class="title">💡</div>
</td>
<td class="content">
<div class="title"><span class="RemarquePreTitre">Pratique</span> Sélection de modules npm</div>
<div class="paragraph">
<p>J’ai compilé une liste de modules utiles pour mieux démarrer
dans vos projets.
Vous la trouverez en <a href="../appendix-a/index.html">annexe A</a>.</p>
</div>
</td>
</tr>
</table>
</div>
</div>
<div class="sect2">
<h3 id="uninstall">2.3. Désinstaller un module</h3>
<div class="paragraph">
<p>
</p>
</div>
<div class="paragraph">
<p>L’utilisation de la commande <code>npm uninstall</code> supprime en toute sécurité
un module <code>npm</code> et les fichiers qu’il a installés.
La commande le retire ensuite de la liste des dépendances
du fichier <code>package.json</code>.</p>
</div>
<div class="listingblock">
<div class="content">
<pre><span data-bash-subs="$"></span>npm uninstall cowsay
removed 10 packages in 1.963s
found 0 vulnerabilities</pre>
</div>
</div>
<div class="paragraph">
<p>Le module <em>cowsay</em> n’est plus installé.
Que se passe-t-il si nous exécutons à nouveau un l’exemple <code>cow.js</code> ?</p>
</div>
<div class="listingblock">
<div class="content">
<pre><span data-bash-subs="$"></span>node cow.js
internal/modules/cjs/loader.js:596
throw err;
^
Error: Cannot find module 'cowsay'</pre>
</div>
</div>
<div class="paragraph">
<p></p>
</div>
<div class="paragraph">
<p>Le chargement du module a échoué car Node n’arrive pas à le trouver
– et c’est normal.</p>
</div>
<div class="paragraph">
<p>Nous devons relancer la commande <code>npm install cowsay</code>
pour que le script fonctionne à nouveau.</p>
</div>
</div>
<div class="sect2">
<h3 id="install">2.4. Depuis un fichier <code>package.json</code></h3>
<div class="paragraph">
<p>
</p>
</div>
<div class="paragraph">
<p>Jusqu’à présent, nous avons installé des modules en les ajoutant un par un.
La procédure est légèrement différente quand nous installons le projet de zéro
ou quand le fichier <code>package.json</code> a été mis à jour par un·e collègue, par exemple.</p>
</div>
<div class="paragraph">
<p>L’exemple suivant illustre la remise à zéro des modules
utilisés en exemple de ce chapitre :</p>
</div>
<div class="listingblock">
<div class="content">
<pre><span data-bash-subs="$"></span>cd $(nodebook dir {chapter-id} --root)
<span data-bash-subs="$"></span>rm -rf node_modules
<span data-bash-subs="$"></span>npm install
added 164 packages from 583 contributors in 4.781s
found 0 vulnerabilities</pre>
</div>
</div>
<div class="paragraph">
<p>Nous nous sommes positionnés dans un répertoire qui contient
un fichier <code>package.json</code> puis nous avons supprimé tout ce qui aurait pu
être installé.</p>
</div>
<div class="paragraph">
<p>La commande <code>npm install</code> s’utilise de manière systématique quand
nous récupérons du code avec Git pour la première fois (<code>git clone</code>)
ou après une mise à jour, par exemple avec <code>git pull</code>.</p>
</div>
<div class="paragraph">
<p>L’exécutable <code>npm</code> vérifie que la correspondance est bien respectée
entre ce qui est installé dans le répertoire <code>node_modules</code> et
les modules listés dans le fichier <code>package.json</code>.
La commande <code>npm install</code> installe, met à jour et retire les modules nécessaires.</p>
</div>
<div class="admonitionblock tip">
<table>
<tr>
<td class="icon">
<div class="title">💡</div>
</td>
<td class="content">
<div class="title"><span class="RemarquePreTitre">Pratique</span> npm clean-install (npm ci)</div>
<div class="paragraph">
<p>
La commande <code>npm clean-install</code> réinstalle un projet de zéro de manière prédictible.
<a href="#ci">Nous y reviendrons plus loin</a>.</p>
</div>
</td>
</tr>
</table>
</div>
</div>
<div class="sect2">
<h3 id="install.version">2.5. Spécifier une version</h3>
<div class="paragraph">
<p></p>
</div>
<div class="paragraph">
<p>Par défaut, l’exécutable <code>npm</code> installe la dernière version d’un module.
Nous avons la liberté d’en installer d’autres qui sont antérieures.
C’est pratique quand des modules arrêtent de prendre en charge
des navigateurs web ou des versions de Node alors que nous les utilisons encore.</p>
</div>
<div class="paragraph">
<p>Nous allons nous servir du module <em>lodash</em> (<span class="URL"><a href="https://npmjs.com/lodash" class="bare">npmjs.com/lodash</a></span>)
pour illustrer nos allées et venues entre différentes versions.
À l’heure où j’écris ces lignes, sa version la plus récente est la <code>4.17.11</code>.
C’est ce que rapporte le résultat de la commande <code>npm install lodash</code> :</p>
</div>
<div class="listingblock">
<div class="content">
<pre><span data-bash-subs="$"></span>npm install lodash
+ lodash@4.17.11</pre>
</div>
</div>
<div class="paragraph">
<p>L’utilisation du caractère <code>@</code> conjointement à un numéro de version précise
la version à installer :</p>
</div>
<div class="listingblock">
<div class="content">
<pre><span data-bash-subs="$"></span>npm install lodash@3.0.0
+ lodash@3.0.0</pre>
</div>
</div>
<div class="paragraph">
<p>Nous avons installé une version précise, mais il y a sûrement des mises à jour
qui ont suivi pour corriger des bogues.
Le problème est que, à ce stade, nous ne connaissons pas le numéro de version
à spécifier.
Idéalement, je préférerais installer la version la plus récente de la série 3.
Il se trouve que l’exécutable <code>npm</code> sait le faire pour nous et sans effort :</p>
</div>
<div class="listingblock">
<div class="content">
<pre><span data-bash-subs="$"></span>npm install lodash@3
+ lodash@<mark>3.10.1</mark></pre>
</div>
</div>
<div class="paragraph">
<p>Nous pouvons faire la même chose avec les versions les plus récentes de
la série 3 et de la série 2.2 :</p>
</div>
<div class="listingblock">
<div class="content">
<pre><span data-bash-subs="$"></span>npm install lodash@3
+ lodash@3.10.1
<span data-bash-subs="$"></span>npm install lodash@2.2
+ lodash@2.2.1</pre>
</div>
</div>
<div class="admonitionblock tip">
<table>
<tr>
<td class="icon">
<div class="title">💡</div>
</td>
<td class="content">
<div class="title"><span class="RemarquePreTitre">Pratique</span> Connaître toutes les versions d’un module</div>
<div class="paragraph">
<p>
La <a href="#view">commande <code>npm view</code></a> affiche les informations d’un module <code>npm</code>
directement depuis notre terminal.
Elle affiche toutes les versions publiées avec l’argument <code>versions</code> :</p>
</div>
<div class="listingblock">
<div class="content">
<pre><span data-bash-subs="$"></span>npm view lodash <mark>versions</mark>
[ '0.1.0',
'0.2.0',
...
'1.0.0',
'1.0.1',
'1.0.2',
... ]</pre>
</div>
</div>
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>Revenons à la version la plus récente en réutilisant la
<a href="#install">commande d’installation</a> abordée auparavant :
</p>
</div>
<div class="listingblock">
<div class="content">
<pre><span data-bash-subs="$"></span>npm install lodash
+ lodash@2.4.2</pre>
</div>
</div>
<div class="paragraph">
<p>Quelque chose d’inattendu s’est produit : la version la plus récente
de la série 2 a été installée au lieu de la version 4.17.11.
Nous trouverons un élément de réponse dans le fichier <code>package.json</code> :
</p>
</div>
<div class="listingblock">
<div class="title">package.json</div>
<div class="content">
<pre class="highlight highlight-prismjs prismjs language-json"><code class="language-json" data-lang="json">{
...
"dependencies": {
"cowsay": "^1.3.1",
"lodash": "<mark>^2.4.2</mark>"
}
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>L’exécutable <code>npm</code> respecte la version indiquée dans le fichier <code>package.json</code>
si aucune autre n’est précisée dans la commande.
Si la dépendance n’est pas listée, alors l’exécutable <code>npm</code> installe la version
la plus récente.</p>
</div>
<div class="paragra