Zbudowałem stosunkowo niewielki pakiet NPM składający się z około 5 różnych klas ES6 zawartych w jednym pliku, wszystkie wyglądają mniej więcej tak:
export default class MyClass {
// ...
}
Następnie skonfigurowałem punkt wejścia dla mojego pakietu, który wygląda następująco:
export { default as MyClass } from './my-class.js';
export { default as MyOtherClass } from './my-other-class.js';
Następnie uruchomiłem punkt wejścia przez webpack i babel, kończąc na transpilowanym i zminimalizowanym pliku index.js
Instalowanie i importowanie pakietu działa dobrze, ale gdy wykonam następujące czynności z kodu mojego klienta:
import { MyClass } from 'my-package';
Nie tylko importuje „MyClass”, ale importuje cały plik, w tym wszystkie zależności każdej klasy (niektóre z moich klas mają ogromne zależności).
Doszedłem do wniosku, że tak działa webpack, gdy próbujesz zaimportować części już dołączonego pakietu? Skonfigurowałem więc moją lokalną konfigurację webpacka, aby działała również node_modules/my-package
przez Babel, a następnie spróbowałem:
import { MyClass } from 'my-package/src/index.js';
Ale nawet to importuje każdą pojedynczą klasę eksportowaną przez index.js. Jedyne, co wydaje się działać tak, jak chcę, to jeśli:
import MyClass from 'my-package/src/my-class.js';
Ale wolałbym:
- Mogę zaimportować transpilowany i zminimalizowany plik, aby nie musiałem mówić webpackowi, aby uruchomił babel wewnątrz node_modules i
- Mogę importować każdą indywidualną klasę bezpośrednio z mojego punktu wejścia zamiast konieczności wprowadzania ścieżki do każdego pliku
Jaka jest tutaj najlepsza praktyka? Jak inni osiągają podobne ustawienia? Zauważyłem, że GlideJS ma wersję pakietu ESM, która pozwala importować tylko to, czego potrzebujesz, bez konieczności uruchamiania na przykład babel.
Pakiet, o którym mowa: https://github.com/powerbuoy/sleek-ui
webpack.config.js
const path = require('path');
module.exports = {
entry: {
'sleek-ui': './src/js/sleek-ui.js'
},
output: {
filename: '[name].js',
path: path.resolve(__dirname, 'dist'),
library: 'sleek-ui', // NOTE: Before adding this and libraryTarget I got errors saying "MyClass() is not a constructor" for some reason...
libraryTarget: 'umd'
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: [
{
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env']
}
}
]
}
]
}
};
pakiet.json
"name": "sleek-ui",
"version": "1.0.0",
"description": "Lightweight SASS and JS library for common UI elements",
"main": "dist/sleek-ui.js",
"sideEffects": false, // NOTE: Added this from Abhishek's article but it changed nothing for me :/
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "webpack --mode production"
},
"repository": {
"type": "git",
"url": "git+https://github.com/powerbuoy/sleek-ui.git"
},
"author": "Andreas Lagerkvist",
"license": "GPL-2.0-or-later",
"bugs": {
"url": "https://github.com/powerbuoy/sleek-ui/issues"
},
"homepage": "https://github.com/powerbuoy/sleek-ui#readme",
"devDependencies": {
"@babel/core": "^7.8.6",
"@babel/preset-env": "^7.8.6",
"babel-loader": "^8.0.6",
"webpack": "^4.42.0",
"webpack-cli": "^3.3.11"
},
"dependencies": {
"@glidejs/glide": "^3.4.1",
"normalize.css": "^8.0.1"
}
}
źródło
main
atrybut (punkt wejścia) do pliku.jpg w bibliotece lib? Sprawdź swoją wersję. Jak pakujesz swój pakiet lib?import { MyClass } from 'my-package/src/MyClass';
. Możesz także usunąć pakiet kompilacji src, aby skrócić ścieżkę pliku.Odpowiedzi:
Tak, sposób, w jaki go skonfigurowałeś, polega na importowaniu każdej klasy z pliku index.js, który jest następnie transponowany do jednego pliku (jeśli jest przeznaczony na ES5, co jest najczęstsze *). Oznacza to, że po zaimportowaniu tego pliku do innego pliku, pojawia się w całości wraz ze wszystkimi tymi klasami.
Jeśli chcesz odpowiednio wstrząsnąć drzewem, powinieneś unikać transpilowania go do pakietu CommonJS (ES5). Sugeruję, aby zachować moduły ES6, same lub w innym miejscu niż pakiet ES5. Ten artykuł powinien pomóc Ci w pełni to zrozumieć i zawiera zalecane instrukcje. Zasadniczo sprowadza się to do ustawienia środowiska Babel za pomocą preset-env (wysoce zalecane, jeśli jeszcze go nie używasz!), Aby zachować składnię ES6 . Oto odpowiednia konfiguracja Babel, jeśli nie chcesz transponować na ES5:
W artykule szczegółowo opisano, jak skonfigurować 2 pakiety, z których każdy używa innej składni modułu.
Warto również zauważyć, i jest również wspomniany w artykule, możesz ustawić punkt wejścia modułu ES w pakiecie.json. To informuje Webpack / Babel, gdzie można znaleźć moduły ES6, co może być wszystkim, czego potrzebujesz w twoim przypadku użycia. Wydaje się, że konwencjonalna mądrość mówi:
Ale dokumentacja węzła ma następującą postać:
Gdybym miał czas, pobawiłbym się tym i sprawdził, który działa poprawnie, ale to powinno wystarczyć, aby ustawić właściwą ścieżkę.
* Pakiety ukierunkowane na ES5 są w formacie CommonJS, który musi zawierać wszystkie powiązane pliki, ponieważ ES5 nie ma natywnej obsługi modułów. Tak było w ES2015 / ES6.
źródło
targets.esmodules: true
i chociaż wprowadziłem zmiany do wbudowanego skryptu, nie zmieniło to, co ostatecznie zostało zaimportowane. Import jednej klasy zmy-package
nadal importuje wszystko. Próbowałem też zmian wpackage.json
(wraz z inną zmianą) i to też niczego nie zmieniło. Cóż, dodanietype: module
faktycznie zepsuło moją kompilację z „Musi użyć importu, aby załadować moduł ES: /sleek-ui/webpack.config.js wymaga () modułów ES nie jest obsługiwane”. więc musiałem to usunąć. Rzucę okiem na linkowany artykuł.modules: false
(nie w środkutargets
), ale to też nie zadziałało ... Myślę, że po prostu zaimportuję bezpośrednio z pliku źródłowego i będę dalej uruchamiał babel przez node_modules, dopóki nie będziemy mogli używać tych rzeczy natywnie.import MyClass from 'my-package/myClass';
. Dobrym przykładem tego jest repozytorium .To jest ważny przypadek użycia. Ostatecznym celem jest to zrobić,
import { MyClass } from 'my-package'
ale istnieje czystszy sposób na zrobienie tego.Utwórz plik indeksu agregatora w swoim
my-package
. Zasadniczomy-package/index.js
i powinno to wyglądać tak:To możesz zrobić
import { MyClass } from 'my-package'
. Bułka z masłem.Baw się dobrze!
źródło