javascript - Hvordan publisere en modul skrevet i ES6 til NPM?
Jeg var i ferd med å publisere en modul til NPM, da jeg tenkte på å skrive den om i ES6, både for å gjøre den fremtidssikker og for å lære ES6. Jeg har brukt Babel til å transpile til ES5, og kjøre tester. Men jeg er ikke sikker på hvordan jeg skal gå videre:
- Skal jeg transpile, og publisere den resulterende /out-mappen til NPM?
- Skal jeg inkludere resultatmappen i Github-repoet mitt?
- Eller skal jeg opprettholde 2 repos, en med ES6-koden + gulp-skriptet for Github, og en med de transpilerte resultatene + tester for NPM?
Kort sagt: hvilke trinn må jeg ta for å publisere en modul skrevet i ES6 til NPM, samtidig som jeg fortsatt lar folk bla gjennom/forke den originale koden?
Svar #1
Mønsteret jeg har sett så langt er å beholde ES6-filene i en src-mappe og bygge tingene dine i npm's prepublish til lib-mappen.
Du vil trenge en .npmignore-fil, lignende .gitignore, men som ignorerer src i stedet for lib.
Svar #2
Jeg liker José sitt svar. Jeg har lagt merke til at flere moduler allerede følger det mønsteret. Slik kan du enkelt implementere det med Babel6. Jeg installerer babel-cli lokalt slik at byggingen ikke bryter hvis jeg noen gang endrer min globale Babel-versjon.
.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": "babel src --out-dir lib"
},
"babel": {
"presets": ["es2015"]
}
}
Svar #3
TL;DR - Ikke gjør det, før omtrent oktober 2019. Node.js-modulteamet har spurt:
Vennligst publiser ikke noen ES-modulpakker ment for bruk med Node.js før [oktober 2019]
Oppdatering mai 2019
Siden 2015 da dette spørsmålet ble stilt, har JavaScript-støtten for moduler modnet betydelig, og forhåpentligvis vil den bli offisielt stabil i oktober 2019. Alle andre svar er nå utdaterte eller altfor kompliserte. Her er den nåværende situasjonen og beste praksis.
ES6-støtte
99 % av ES6 (også kjent som 2015) har blitt støttet av Node siden versjon 6. Den nåværende versjonen av Node er 12. Alle moderne nettlesere støtter det store flertallet av ES6-funksjonene. ECMAScript er nå på versjon 2019, og versjonssystemet favoriserer nå bruk av årstall.
ES-moduler (også kjent som ECMAScript-moduler) i nettlesere
Alle moderne nettlesere har støttet import-ering av ES6-moduler siden 2017. Dynamiske imports støttes av Chrome (+ avleggere som Opera og Samsung Internet) og Safari. Støtte i Firefox er planlagt for neste versjon, 67.
Du trenger ikke lenger Webpack/rollup/Parcel osv. for å laste moduler. De kan fortsatt være nyttige for andre formål, men er ikke nødvendige for å laste koden din. Du kan direkte importere URL-er som peker til ES-moduler kode.
ES-moduler i Node
ES-moduler (.mjs-filer med import/export) har blitt støttet siden Node v8.5.0 ved å kjøre node med --experimental-modules-flagget. Node v12, utgitt i april 2019, omskrev støtten for eksperimentelle moduler. Den mest synlige endringen er at filendelsen må spesifiseres som standard når man importerer:
// lib.mjs
export const hello = 'Hello world!';
// index.mjs:
import { hello } from './lib.mjs';
console.log(hello);
Merk de påkrevde .mjs-utvidelsene gjennomgående. Kjør som:
node --experimental-modules index.mjs
Node 12-utgivelsen er også når Moduler-teamet ba utviklere om ikke å publisere ES-modulpakker ment for bruk av Node.js før en løsning er funnet for å bruke pakker via både require('pkg') og import 'pkg'. Du kan fortsatt publisere native ES-moduler ment for nettlesere.
Økosystemstøtte for native ES-moduler
Per mai 2019 er økosystemstøtten for ES-moduler umoden. For eksempel støtter ikke test-rammeverk som Jest og Ava --experimental-modules. Du må bruke en transpiler, og må deretter velge mellom å bruke navngitt import (import { symbol }) syntaks (som ennå ikke fungerer med de fleste npm-pakker), og standard import-syntaks (import Package from 'package'), som fungerer, men ikke når Babel parser det for pakker skrevet i TypeScript (graphql-tools, node-influx, faast osv.). Det finnes imidlertid en løsning som fungerer både med --experimental-modules og hvis Babel transpilerer koden din, slik at du kan teste det med Jest/Ava/Mocha osv:
import * as ApolloServerM from 'apollo-server'; const ApolloServer = ApolloServerM.default || ApolloServerM;
Muligens stygt, men på denne måten kan du skrive din egen ES-modulkode med import/export og kjøre den med node --experimental-modules, uten transpileringsverktøy. Hvis du har avhengigheter som ennå ikke er ESM-klare, importer dem som ovenfor, og du vil kunne bruke testverktøy og annen verktøy via Babel.
Forrige svar på spørsmålet - husk, ikke gjør dette før Node løser require/import-problemet, forhåpentligvis rundt oktober 2019.
Publisering av ES6-moduler til npm, med bakoverkompatibilitet
For å publisere en ES-modul til npmjs.org slik at den kan importeres direkte, uten Babel eller andre transpileringsverktøy, pek ganske enkelt main-feltet i din package.json til .mjs-filen, men utelat filtypen:
{
"name": "mjs-example",
"main": "index"
}
Det er den eneste endringen. Ved å utelate filtypen, vil Node først se etter en mjs-fil dersom den kjøres med --experimental-modules. Ellers vil den falle tilbake til .js-filen, så din eksisterende transpileringsprosess for å støtte eldre Node-versjoner vil fungere som før — bare sørg for å peke Babel til .mjs-filene.
Her er kilden for en native ES-modul med bakoverkompatibilitet for Node < 8.5.0 som jeg publiserte til NPM. Du kan bruke den med en gang, uten Babel eller noe annet.
Installer modulen:
npm install local-iso-dt
or, yarn add local-iso-dt
Opprett en testfil test.mjs:
import { localISOdt } from 'local-iso-dt/index.mjs';
console.log(localISOdt(), 'Starting job...');
Kjør node (v8.5.0+) med flagget --experimental-modules:
node --experimental-modules test.mjs
TypeScript
Hvis du utvikler i TypeScript, kan du generere ES6-kode og bruke ES6-moduler:
tsc index.js --target es6 --modules es2015
Deretter må du gi nytt navn til *.js-utdataene til .mjs, et kjent problem som forhåpentligvis blir fikset snart, slik at tsc kan generere .mjs-filer direkte.
Svar #4
@Jose har rett. Det er ingenting galt med å publisere ES6/ES2015 til NPM, men det kan forårsake problemer, spesielt hvis personen som bruker pakken din bruker Webpack, for eksempel, fordi folk vanligvis ignorerer node_modules-mappen mens de forhåndsprosesserer med babel av ytelsesårsaker.
Så, bruk bare gulp, grunt eller rett og slett Node.js for å bygge en lib-mappe som er ES5.
Her er mitt build-lib.js-skript, som jeg holder i ./tools/ (ingen gulp eller grunt her):
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));
Her er et siste råd: Du må legge til en .npmignore i prosjektet ditt. Hvis npm publish ikke finner denne filen, vil det bruke .gitignore i stedet, noe som vil forårsake problemer fordi normalt vil .gitignore-filen din ekskludere ./lib og inkludere ./src, noe som er nøyaktig det motsatte av det du vil når du publiserer til NPM. .npmignore-filen har i hovedsak samme syntaks som .gitignore (så vidt jeg vet).
Svar #5
Følger José og Marius sin tilnærming, (med oppdatering av Babel sin siste versjon i 2019): Behold de nyeste JavaScript-filene i en src-katalog, og bygg med npms prepublish-script og output til lib-katalogen.
.npmignore
/src
.gitignore
/lib
/node_modules
Installer Babel (versjon 7.5.5 i mitt tilfelle)
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"
]
}
}
Og jeg har src/index.js som bruker piltasten funksjonen:
"use strict";
let NewOneWithParameters = (a, b) => {
console.log(a + b); // 30
};
NewOneWithParameters(10, 20);
Her er repositoriet på GitHub.
Nå kan du publisere pakken:
npm publish
...
> [email prepublish .
> babel src -d lib
Successfully compiled 1 file with Babel.
...
Før pakken publiseres til npm, vil du se at lib/index.js har blitt generert, som er transpilert til es5:
"use strict";
var NewOneWithParameters = function NewOneWithParameters(a, b) {
console.log(a + b); // 30
};
NewOneWithParameters(10, 20);
[Oppdatering for Rollup-bunter]
Som spurt av @kyw, hvordan ville du integrert Rollup-bundleren?
Først, installer rollup og rollup-plugin-babel
npm install -D rollup rollup-plugin-babel
For det andre, opprett rollup.config.js i prosjektets rotmappe
import babel from "rollup-plugin-babel";
export default {
input: "./src/index.js",
output: {
file: "./lib/index.js",
format: "cjs",
name: "bundle"
},
plugins: [
babel({
exclude: "node_modules/**"
})
]
};
Til slutt, oppdater prepublish i package.json
{
...
"scripts": {
"prepublish": "rollup -c"
},
...
}
Nå kan du kjøre npm publish, og før pakken publiseres til npm, vil du se at lib/index.js har blitt generert, som er transpilt til es5:
'use strict';
var NewOneWithParameters = function NewOneWithParameters(a, b) {
console.log(a + b); // 30
};
NewOneWithParameters(10, 20);
Merk: forresten, du trenger ikke lenger @babel/cli hvis du bruker Rollup-bundleren. Du kan trygt avinstallere den:
npm uninstall @babel/cli
