Jak npm opublikować określony folder, ale jako katalog główny pakietu

86

Mam projekt, który obejmuje proste zadanie tworzenia i pakowania źródeł oraz wydawania w katalogu o nazwie dist. Moim celem jest opublikowanie go jako pakietu npm, ale tylko mój folder dist. Dokumentacja npm mówi, że mogę użyć filestagu do określenia plików do wyeksportowania. To działa. Ale dokumentacja mówi również, że:

Jeśli nazwiesz folder w tablicy, będzie on również zawierał pliki w tym folderze

Rezultatem jest pakiet npm, którego node_modules wygląda następująco:

wygenerowany pakiet npm

Ale chciałbym widzieć wszystkie moje pliki w katalogu głównym pakietu (bez tego distfolderu). Mój index.jsplik znajduje się w distfolderze, ale powinien znajdować się w katalogu głównym. Próbowałem ustawić tagfiles jako, /dist/**/*ale to nie zadziałało.

Jak mogę to osiągnąć?

robsonrosa
źródło

Odpowiedzi:

44

Mam to samo pragnienie, ale myślę, że nie ma sposobu, aby to osiągnąć przy użyciu tylko narzędzi npm . Do zaaranżowania pakietu można użyć innego skryptu / narzędzia.

Alternatywne rozwiązanie

Obecnie kopiuję plik package.jsondo distfolderu, a następnie uruchamiam go npm packw distfolderze. Myślę, że to zasadniczo zapewnia pożądany układ naszego pakietu.

Oto kilka istotnych informacji na temat tego projektu npm: Why no Directories.lib in Node .

Warto również zauważyć, że jspm DOTYCZY directories.libopcji wi rearanżuje package.jsonpliki podczas rozwiązywania pakietu npm. To wszystko wydarzyło się dla mnie, ponieważ chcę zbudować wspólną bibliotekę, która może być używana przez jspm lub npm / webpack.

scvnc
źródło
1
(Why no Directories.lib ...) to martwy link
Shanimal
1
Dlaczego żaden katalog Directories.lib w Node nie mówi, jeśli nie robisz tego po swojemu, powinieneś czuć ból. Wszystko to stwarza potrzebę narzędzi do obejścia tego problemu.
Brian Takita
6
Uważam, że ta odpowiedź jest nieaktualna. Jak zauważają poniższe odpowiedzi, użycie npm pack, package.json filesi mainfields, .npmignoredaje programiście wszystko, co jest potrzebne do utworzenia pakietu z określonego katalogu, który można zainstalować.
Jefftopia
1
Zrobiłem kilka skryptów, aby usprawnić / wymusić wzorzec „publikuj podkatalog”
zmikimalizuj
2
Czy ktoś może opublikować rozwiązanie, w jaki sposób można to osiągnąć za pomocą npmignore, plików i głównej właściwości w package.json. Chcę przenieść cały plik do katalogu głównego i nie mam folderu dist
Angad
16

Mam podobny problem do oryginalnego plakatu (@robsonrosa). W moim przypadku używam typecript, który kompiluje do distkatalogu. Chociaż mógłbym skompilować maszynę do katalogu głównego, myślę, że najlepszym rozwiązaniem jest wygenerowanie oddzielnego package.jsonpliku w katalogu dist.
Jest to podobne do sugestii @scvnc, aby skopiować plik, package.jsonale z niespodzianką :

W ramach procesu pakowania należy wygenerować package.jsondla pakietu, który jest oparty na głównym package.jsonpliku w katalogu głównym, ale różni się od niego

Uzasadnienie:

  • Plik główny package.jsonjest plikiem deweloperskim. Może zawierać skrypty lub zależności programistyczne, które nie są przydatne dla użytkownika pakietu, ale mogą stanowić zagrożenie dla Ciebie. Twoja procedura pakowania może obejmować kod, który usuwa te informacje z produkcjipackage.json .
  • Możesz chcieć wdrożyć swój pakiet w różnych środowiskach, które mogą wymagać różnych plików pakietów (np. Możesz chcieć mieć różne wersje lub zależności).

--- EDYTOWAĆ ---

W komentarzach poproszono mnie o rozwiązanie. Oto kod, którego używam. Należy to traktować jako przykład. Nie ma być ogólny i jest specyficzny dla moich projektów.

Moja konfiguracja:

package.json         - main package.json with dev dependencies and useful scripts.
.npmignore           - files to ignore; copied to 'dist' directory as part of the setup.
/src                 - directory where my typescript code resides.
/src/SetupPackage.ts - bit of code used to setup the package.
/dist                - destination directory for the compiled javascript files.

Chcę spakować tylko distkatalog, a katalog powinien być katalogiem głównym w pakiecie.

Plik SetupPackage.tsw moim srckatalogu zostaną skompilowane do SetupPackage.jsw distkatalogu przez maszynopisu:

import fs from "fs";

// DO NOT DELETE THIS FILE
// This file is used by build system to build a clean npm package with the compiled js files in the root of the package.
// It will not be included in the npm package.

function main() {
    const source = fs.readFileSync(__dirname + "/../package.json").toString('utf-8');
    const sourceObj = JSON.parse(source);
    sourceObj.scripts = {};
    sourceObj.devDependencies = {};
    if (sourceObj.main.startsWith("dist/")) {
        sourceObj.main = sourceObj.main.slice(5);
    }
    fs.writeFileSync(__dirname + "/package.json", Buffer.from(JSON.stringify(sourceObj, null, 2), "utf-8") );
    fs.writeFileSync(__dirname + "/version.txt", Buffer.from(sourceObj.version, "utf-8") );

    fs.copyFileSync(__dirname + "/../.npmignore", __dirname + "/.npmignore");
}

main();

Ten plik:

  • Kopiuje root, package.jsonale usuwa skrypty i zależności dev, które nie są potrzebne w pakiecie. Naprawia również główny punkt wejścia do pakietu.
  • Zapisuje wersję pakietu z package.jsondo pliku o nazwie version.txt.
  • Kopiuje .npmignorepakiet z katalogu głównego.

Zawartość .npmignore to:

*.map
*.spec.*
SetupPackage.*
version.txt

Tj. Testy jednostkowe (pliki specyfikacji) i pliki map maszynopisów są ignorowane, podobnie jak SetupPackage.jsplik i version.txtplik, który tworzy. To pozostawia czysty pakiet.

Wreszcie główny package.jsonplik zawiera następujące skrypty do użytku przez system kompilacji (zakłada, że shjest używany jako powłoka).

"scripts": {
    "compile": "tsc",
    "clean": "rm -rf dist",
    "prebuildpackage": "npm run clean && npm run compile && node dist/SetupPackage.js",
    "buildpackage": "cd dist && npm pack"
  },

Aby zbudować pakiet, system kompilacji klonuje repozytorium, wykonuje, npm installa następnie uruchamia, npm run buildpackageco z kolei:

  • Usuwa distkatalog, zapewniając czystą kompilację.
  • Kompiluje kod maszynopisu do javascript.
  • Wykonuje SetupPackage.jsplik, który przygotowuje się distdo pakowania.
  • cds do distkatalogu i tam buduje pakiet.

Używam tego version.txtpliku jako łatwego sposobu na pobranie wersji w package.json i otagowanie mojego repozytorium. Istnieje wiele innych sposobów, aby to zrobić, lub możesz chcieć automatycznie zwiększyć wersję. Usuń to z SetupPackage.tsi .npmignorejeśli nie jest to dla Ciebie przydatne.

Eli Algranti
źródło
Ta odpowiedź wygląda na najlepszą, ale czy masz gotowe rozwiązanie poza teorią?
yumaa
3
@yumaa Zmieniłem odpowiedź, podając konkretny przykład. Mam nadzieję, że to przydatne.
Eli Algranti
13

Jeśli twój projekt ma git, możesz użyć małego hacka. Dodaj kolejne skrypty do pliku package.json

    "prepublishOnly": "npm run build && cp -r ./lib/* . && rm -rf ./lib",
    "postpublish": "git clean -fd",

teraz, kiedy uruchamiasz publishpolecenie npm include prepublishOnly. Buduje pliki i zapisuje je w libfolderze (skrypt kompilacji zależy od projektu). Następne polecenie kopiuje pliki do folderu głównego i usuwa lib. Po opublikowaniu postpublishskrypt przywraca projekt do poprzedniego stanu.

Legowisko
źródło
1
Jestem fanem tego rozwiązania!
DanMad
6

Zdecydowanie zalecam używanie .npmignorezamiast przenoszenia lub kopiowania rzeczy, szczególnie jeśli używasz CI do wdrożeń, i po prostu dodaj tam pliki, których nie chcesz publikować.

https://docs.npmjs.com/misc/developers#keeping-files-out-of-your-package

Przykład:

#tests
test
coverage

#build tools
.travis.yml
.jenkins.yml
.codeclimate.yml

#linters
.jscsrc
.jshintrc
.eslintrc*

#editor settings
.idea
.editorconfig

Aktualizacja:

Jeśli chcesz podzielić swój kod na różne pakiety npm przy użyciu tego samego repozytorium, wpadłem ostatnio na ten projekt: Lerna i wygląda naprawdę dobrze.

Może powinieneś rzucić okiem

Thram
źródło
9
Nadal musielibyśmy emitować nasze wbudowane pliki w katalogu głównym pakietu. Być może dopuszczalne dla CI. Obserwuj post z bloga Isaaca, do którego require('mypackage/foo')require('mypackage/dist/foo')
utworzyłem
Nie próbowałem tutaj rozwiązać tego problemu. Jeśli chcesz podzielić swój kod, wpadłem ostatnio na ten projekt: lernajs.io i wygląda naprawdę dobrze
Thram
Znalazłem inne narzędzie, które warto zobaczyć :) github.com/philcockfield/msync
Thram
yeh Material UI używam go i użyłem tego w mojej ostatniej firmie, znalazłem to ok
nick
5

U mnie to działa dobrze.

cd TMPDIR; npm pack/path/to/package.json

Tarball utworzy w katalogu TMPDIR.

Nadeeshan Gimhana
źródło
^ Ta odpowiedź jest niedoceniana. npm packplus filespole package.json (lub .npmignore) działa wspaniale.
Jefftopia,
1

Musisz opublikować distfolder

Naturalnym sposobem osiągnięcia tego, zgodnie z podejściem npm, jest opublikowanie folderu, który ma być katalogiem głównym. Można to zrobić na kilka sposobów, w zależności od końcowego środowiska, z którym chcesz pracować:

  1. npm publikuj <folder> z repozytorium pakietów do rejestru npm, a następnie zainstaluj pakiet w innym projekcie podczas instalowania innych pakietów. W twoim przypadku tak by byłonpm publish dist .
  2. npm install <folder> w jakimś innym projekcie, jeśli chcesz używać swojego pakietu tylko lokalnie. W twoim przypadku przechodzisz do innego projektu i uruchamiasznpm install relative/path/to/dist
  3. npm połącz swój folder lokalnie z Twoim node_modulesw innym projekcie, na wypadek gdybyś chciał, aby zmiany w oryginalnym pakiecie zostały natychmiast odzwierciedlone w innym projekcie. W twoim przypadku najpierw cd disturuchamiasz, npm linka potem przechodzisz do innego projektu i uruchamiasz npm link robsonrosa-ui-alert.

Warunek wstępny : w każdym przypadku powyżej, przed opublikowaniem / instalacją / linkiem, musisz umieścić w swoim distfolderze co najmniej odpowiedni package.jsonplik. W twoim przypadku musisz mieć nazwę pakietu zdefiniowaną w pliku package.json jako "name": "robsonrosa-ui-alert". Zwykle będziesz potrzebować także innych plików, takich jak README.md lub LICENCJA.

Przykład automatyzacji

Możesz zautomatyzować proces publikacji za pomocą prepareskryptu w połączeniu ze buildskryptem. Dodatkowo możesz zabezpieczyć swój pakiet przed przypadkowym opublikowaniem głównego folderu pakietu, wpisując "private": truepole w pliku package.json, znajdującym się w katalogu głównym repozytorium pakietów. Oto przykład:

  "private": true,
  "scripts": {
    "build": "rm -rf dist && gulp build && cat ./package.json | grep -v '\"private\":' > dist/package.json",
    "prepare": "npm run build"
  },

W ten sposób nie opublikujesz folderu głównego i nie otrzymasz skompilowanego pakietu i pliku package.json skopiowanego do distfolderu automatycznie w trakcie procesu publikowania.

Jacek J
źródło
0

opcja 1: przejdź do folderu i wykonaj polecenie „npm opublikuj”. Komenda

opcja 2: Uruchom npm publikacja / ścieżka / katalog

Sasi Kumar M
źródło
-1

Oto jeszcze jedno podejście, które moim zdaniem jest najczystsze. Wszystko opiera się na konfiguracji bez konieczności przenoszenia plików lub określania ścieżek w skryptach kompilacji i pakowania:

package.json Określ plik główny.

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

Dodatkowe opcje maszynopisu:

  • Określ plik rootDir. Ten katalog będzie zawierał cały kod źródłowy i powinien zawierać indexplik (lub inny plik, którego możesz użyć jako głównego wpackage.json ).
  • Określ plik outDir. To jest miejsce, w którym Twoje polecenie tsc będzie budować

tsconfig.json

{
    "compilerOptions": {
        "rootDir": "src",
        "outDir": "lib",
    },
    ...

}
scottmgerstl
źródło
Czy to nie to samo, co pierwotnie miał OP, z wyjątkiem zmiany nazwy z dist na lib?
Bob9630
-3

Po prostu utwórz .npmignoreplik i dodaj do niego:

*.*
!dist/*
Maurice
źródło
1
czy robi to zgodnie z żądaniem PO? Nie byłem w stanie zmusić tego do pracy. Pomysł polegał na tym, aby opublikowany pakiet zawierał tylko zawartość katalogu dist bez dołączania samego katalogu. Robię to, aby upewnić się, że nie uwzględnimy niczego, czego nie ma w katalogu dist, co można już zrobić z listą plików w pliku package.json.
Bob9630