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:
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?
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
.
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"]
}
}
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].
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.
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.
Tous les navigateurs evergreen ont été supportésimport
ing 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.
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.
À 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.
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
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.
@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 gulp
ou 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).
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.
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
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.
require( 'your-package' )
fonctionne.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>
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);