web-dev-qa-db-fra.com

Comment publier un module écrit en ES6 sur NPM?

J'étais sur le point de publier un module dans NPM, lorsque j'ai pensé le réécrire dans ES6, à la fois pour le mettre à l'épreuve du temps et pour apprendre l'ES6. J'ai utilisé Babel pour transpiler sur ES5 et exécuter des tests. Mais je ne suis pas sûr de savoir comment procéder:

  1. Est-ce que je transpile et publie le dossier résultant/out sur NPM?
  2. Dois-je inclure le dossier de résultats dans mon dépôt Github?
  3. Ou dois-je conserver 2 pensions, une avec le script ES6 code + gulp pour Github et une avec les résultats transpilés + les tests pour NPM?

En bref: quelles étapes dois-je suivre pour publier un module écrit dans ES6 vers NPM, tout en permettant aux utilisateurs de parcourir/insérer le code d'origine?

117
Traveling Tech Guy

Le modèle que j’ai vu jusqu’à présent consiste à conserver les fichiers es6 dans un répertoire src et à créer votre contenu dans la publication préalable de npm dans le répertoire lib.

Vous aurez besoin d'un fichier .npmignore, similaire à .gitignore mais ignorant src au lieu de lib.

66

J'aime la réponse de José. J'ai remarqué que plusieurs modules suivent déjà ce modèle. Voici comment vous pouvez facilement l'implémenter avec Babel6. J'installe babel-cli localement pour que la construction ne se casse pas si je change jamais ma version globale de babel.

. npmignore

/src/

. gitignore

/lib/
/node_modules/

Installer Babel

npm install --save-dev babel-core babel-cli babel-preset-es2015

package.json

{
  "main": "lib/index.js",
  "scripts": {
    "prepublish": "node_modules/babel-cli/bin/babel.js src --out-dir lib"
  },
  "babel": {
    "presets": ["es2015"]
  }
}
63
Marius Craciunoiu

TL; DR - Ne le faites pas avant ~ octobre 2019. Le Node.js Équipe Modules a demandé :

Veuillez ne publier aucun package de module ES destiné à être utilisé par Node.js avant le [octobre 2019].

Mise à jour de mai 2019

Depuis 2015, date à laquelle cette question a été posée, la prise en charge de JavaScript par les modules a considérablement évolué et devrait être officiellement stable en octobre 2019. Toutes les autres réponses sont maintenant obsolètes ou trop compliquées. Voici la situation actuelle et les meilleures pratiques.

Support ES6

99% de l'ES6 (aka 2015) est pris en charge par Node depuis la version 6 . La version actuelle de Node est 12. Tous les navigateurs Evergreen prennent en charge la grande majorité des fonctionnalités de l'ES 6. ECMAScript est maintenant à la version version 2019 , et le schéma de gestion des versions favorise désormais l'utilisation du nombre d'années.

ES Modules (ou modules ECMAScript) dans les navigateurs

Tous les navigateurs evergreen ont été supportésimporting depuis l'ES6 depuis 2017. importations dynamiques sont supportés = by Chrome (+ comme + Opera et Samsung Internet) et Safari Internet) et Safari. La prise en charge de Firefox est prévue pour la prochaine version, 67.

Vous n'avez plus besoin Webpack/rollup/Parcel etc. pour charger des modules. Ils peuvent être encore utiles à d’autres fins, mais ne sont pas obligés de charger votre code. Vous pouvez importer directement des URL pointant vers le code des modules ES.

Modules ES dans le nœud

Les modules ES (fichiers .mjs Avec import/export) sont pris en charge depuis Node v8.5.0 en appelant node avec l'indicateur --experimental-modules. Node v12, publié en avril 2019, réécrit le support des modules expérimentaux. Le changement le plus visible est que l'extension de fichier doit être spécifiée par défaut lors de l'importation :

// lib.mjs 

export const hello = 'Hello world!';

// index.mjs:

import { hello } from './lib.mjs';
console.log(hello);

Notez les extensions obligatoires .mjs Tout au long. Courir comme:

node --experimental-modules index.mjs

La version Node 12 est également disponible lorsque l'équipe de modules demandée les développeurs ne publient pas les packages de module ES destiné à être utilisé par Node.js jusqu'à ce qu'une solution soit trouvée pour l'utilisation de paquets via require('pkg') et import 'pkg'. Vous pouvez toujours publier des modules ES natifs destinés aux navigateurs.

Prise en charge par l'écosystème des modules ES natifs

À compter de mai 2019, le support écosystémique pour les modules ES est immature. Par exemple, des structures de test telles que Jest et Ava ne supportent pas --experimental-modules. Vous devez utiliser un transpiler, puis décider entre l’utilisation de la syntaxe d’importation nommée (import { symbol }) (Qui ne fonctionnera pas encore avec la plupart des paquets npm) et de la syntaxe d’importation par défaut (import Package from 'package' ), qui fonctionne, mais pas lorsque Babel l’analyse pour paquets développés dans TypeScript (graphql-tools, node-influx, faast, etc.) Il existe toutefois une solution de contournement qui fonctionne à la fois avec --experimental-modules et si Babel transcrit votre code afin que vous puissiez le tester avec Jest/Ava/Mocha, etc.:

import * as ApolloServerM from 'apollo-server'; const ApolloServer = ApolloServerM.default || ApolloServerM;

On peut dire que c'est moche, mais de cette façon, vous pouvez écrire votre propre code de module ES avec import/export et l'exécuter avec node --experimental-modules, Sans transpilers. Si vous avez des dépendances qui ne sont pas encore compatibles avec ESM, importez-les comme ci-dessus et vous pourrez utiliser des frameworks de test et d'autres outils via Babel.


Réponse précédente à la question - rappelez-vous, ne le faites pas jusqu'à ce que Node) résolve le problème de nécessité/importation, espérons-le vers octobre 2019.

Publication de modules ES6 sur npm, avec compatibilité ascendante

Pour publier un module ES sur npmjs.org afin qu'il puisse être importé directement, sans Babel ni d'autres transpilers, il vous suffit de pointer le champ main de votre package.json Vers le fichier .mjs. , mais omettez l'extension:

{
  "name": "mjs-example",
  "main": "index"
}

C'est le seul changement. En omettant l’extension, Node recherchera d’abord un fichier mjs s’il est exécuté avec --experimental-modules. Sinon, il tombera dans le fichier .js, de sorte que votre fichier transpilation existant) processus pour prendre en charge les versions antérieures Node fonctionneront comme avant) - assurez-vous simplement de diriger Babel vers le (s) fichier (s) .mjs.

Voici le source d'un module ES natif avec compatibilité ascendante pour Node <8.5. que j'ai publié sur NPM. Vous pouvez l'utiliser maintenant, sans Babel ni quoi que ce soit autre.

Installez le module:

npm install local-iso-dt
# or, yarn add local-iso-dt

Créez un fichier de test test.mjs :

import { localISOdt } from 'local-iso-dt/index.mjs';
console.log(localISOdt(), 'Starting job...');

Exécutez le noeud (v8.5.0 +) avec l'indicateur --experimental-modules:

node --experimental-modules test.mjs

Manuscrit

Si vous développez en TypeScript, vous pouvez générer du code ES6 et utiliser des modules ES6:

tsc index.js --target es6 --modules es2015

Ensuite, vous devez renommer la sortie *.js En .mjs, Un numéro connu qui, espérons-le, sera bientôt corrigé afin que tsc puisse générer .mjs fichiers directement.

24
Dan Dascalescu

@Jose a raison. Il n’ya rien de mal à publier ES6/ES2015 sur NPM, mais cela peut poser problème, en particulier si la personne utilisant votre package utilise Webpack, par exemple, car normalement les personnes ignorent le dossier node_modules Lors du prétraitement avec babel pour des raisons de performances.

Donc, utilisez simplement gulp, grunt ou simplement Node.js pour créer un dossier lib qui est ES5.

Voici mon script build-lib.js, Que je garde dans ./tools/ (No gulpou grunt ici):

var rimraf = require('rimraf-promise');
var colors = require('colors');
var exec = require('child-process-promise').exec;

console.log('building lib'.green);

rimraf('./lib')
    .then(function (error) {
        let babelCli = 'babel --optional es7.objectRestSpread ./src --out-dir ./lib';
        return exec(babelCli).fail(function (error) {
            console.log(colors.red(error))
        });
    }).then(() => console.log('lib built'.green));

Voici un dernier conseil: Vous vous devez ajouter un fichier .npmignore à votre projet. Si npm publish Ne trouve pas ce fichier, il utilisera .gitignore À la place, ce qui vous causera des problèmes car normalement votre fichier .gitignore Exclura ./lib Et inclura ./src, Qui est exactement le contraire de ce que vous voulez lorsque vous publiez sur NPM. Le fichier .npmignore A essentiellement la même syntaxe que .gitignore (Autant que je sache).

16
André Pena

Si vous voulez voir cela en action dans un petit open source très simple Node alors jetez un oeil à nième jour (que j'ai commencé - ainsi que d'autres contributeurs) Regardez dans le fichier package.json et à l'étape de prépublication qui vous mènera à où et comment faire cela. Si vous clonez ce module, vous pouvez l'exécuter localement et l'utiliser comme modèle.

5
Guy

La clé principale dans package.json décide du point d’entrée du paquet une fois publié. Vous pouvez donc placer la sortie de votre Babel où vous voulez et simplement mentionner le bon chemin dans la clé main.

"main": "./lib/index.js",

Voici un article bien écrit sur la publication d'un paquet npm

https://codeburst.io/publish-your-own-npm-package-ff918698d45

Voici un exemple de repo que vous pouvez utiliser pour référence

https://github.com/flexdinesh/npm-module-boilerplate

3
Dinesh Pandiyan

Les deux critères d'un package NPM sont qu'il est utilisable avec rien de plus qu'un require( 'package' ) et qu'il fait quelque chose de logiciel-ish.

Si vous remplissez ces deux conditions, vous pouvez faire ce que vous voulez. Même si le module est écrit en ES6, si l'utilisateur final n'a pas besoin de le savoir, je le transpilerais pour l'instant pour obtenir un support maximal.

Toutefois, si, comme koa , votre module nécessite une compatibilité avec les utilisateurs utilisant les fonctionnalités de ES6, la solution à deux packages serait peut-être une meilleure idée.

À emporter

  1. Ne publiez que la quantité de code nécessaire pour que require( 'your-package' ) fonctionne.
  2. À moins que les ES5 et 6 ne concernent l’utilisateur, ne publiez qu’un seul paquet. Transpilez-le si vous devez.
3
JoshWillik

Selon l’anatomie de votre module, cette solution risque de ne pas fonctionner, mais si votre module est contenu dans un seul fichier et ne comporte pas de dépendances (ne fait pas appel à import ), en utilisant le modèle suivant, vous pouvez publier votre code tel quel et vous pourrez l'importer avec importation (modules ES6 du navigateur) et obligatoire (modules Node CommonJS)

En prime, il sera possible d'importer à l'aide d'un élément HTML SCRIPT.

main.js:

(function(){
    'use strict';
    const myModule = {
        helloWorld : function(){ console.log('Hello World!' )} 
    };

    // if running in NODE export module using NODEJS syntax
    if(typeof module !== 'undefined') module.exports = myModule ;
    // if running in Browser, set as a global variable.
    else window.myModule = myModule ;
})()

my-module.js:

    // import main.js (it will declare your Object in the global scope)
    import './main.js';
    // get a copy of your module object reference
    let _myModule = window.myModule;
    // delete the the reference from the global object
    delete window.myModule;
    // export it!
    export {_myModule as myModule};

package.json: `

    {
        "name" : "my-module", // set module name
        "main": "main.js",  // set entry point
        /* ...other package.json stuff here */
    }

Pour utiliser votre module, vous pouvez maintenant utiliser la syntaxe habituelle ...

Lorsque importé dans NOEUD ...

    let myModule = require('my-module');
    myModule.helloWorld();
    // outputs 'Hello World!'

Lorsque importé dans NAVIGATEUR ...

    import {myModule} from './my-module.js';
    myModule.helloWorld();
    // outputs 'Hello World!'

Ou même lorsqu'il est inclus à l'aide d'un HTML Script Element ...

<script src="./main.js"></script>
<script>
     myModule.helloWorld();
    // outputs 'Hello World!'
</script>
0
colxi

Suivant l'approche de José et Marius, (avec mise à jour de la dernière version de Babel en 2019): Conservez les derniers fichiers JavaScript dans un répertoire src, et construisez-les avec le script prepublish de npm et exportez-les dans le répertoire lib.

. npmignore

/src

. gitignore

/lib
/node_modules

Installez Babel (version 7.5.5 dans mon cas)

$ npm install @babel/core @babel/cli @babel/preset-env --save-dev

package.json

{
  "name": "latest-js-to-npm",
  "version": "1.0.0",
  "description": "Keep the latest JavaScript files in a src directory and build with npm's prepublish script and output to the lib directory.",
  "main": "lib/index.js",
  "scripts": {
    "prepublish": "babel src -d lib"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "@babel/cli": "^7.5.5",
    "@babel/core": "^7.5.5",
    "@babel/preset-env": "^7.5.5"
  },
  "babel": {
    "presets": [
      "@babel/preset-env"
    ]
  }
}

Et j'ai src/index.js qui utilise la fonction flèche:

"use strict";

let NewOneWithParameters = (a, b) => {
  console.log(a + b); // 30
};
NewOneWithParameters(10, 20);

Voici le repo sur GitHub .

Vous pouvez maintenant publier le package:

$ npm publish
...
> [email protected] prepublish .
> babel src -d lib

Successfully compiled 1 file with Babel.
...

Avant que le paquet ne soit publié sur npm, vous verrez que lib/index.js a été généré et est transpilé en es5:

"use strict";

var NewOneWithParameters = function NewOneWithParameters(a, b) {
  console.log(a + b); // 30
};

NewOneWithParameters(10, 20);
0
Yuci