J'ai construit un package NPM relativement petit composé d'environ 5 classes ES6 différentes contenues dans un fichier chacune, elles ressemblent toutes à peu près à ceci:
export default class MyClass {
// ...
}
J'ai ensuite configuré un point d'entrée pour mon package qui ressemble à ceci:
export { default as MyClass } from './my-class.js';
export { default as MyOtherClass } from './my-other-class.js';
J'ai ensuite exécuté le point d'entrée via webpack et babel pour finir avec un index.js transpilé et minifié
L'installation et l'importation du package fonctionnent correctement, mais lorsque je fais ce qui suit à partir de mon code client:
import { MyClass } from 'my-package';
Il ne se contente pas d'importer "MyClass", il importe le fichier entier, y compris toutes les dépendances de chaque classe (certaines de mes classes ont d'énormes dépendances).
Je me suis dit que c'est ainsi que fonctionne le webpack lorsque vous essayez d'importer des parties d'un package déjà fourni? J'ai donc configuré ma configuration de webpack local pour exécuter Babel node_modules/my-package
aussi, puis j'ai essayé:
import { MyClass } from 'my-package/src/index.js';
Mais même cela importe chaque classe exportée par index.js. La seule chose qui semble fonctionner comme je le souhaite, c'est si je le fais:
import MyClass from 'my-package/src/my-class.js';
Mais je préfère de beaucoup:
- Pouvoir importer le fichier transpilé et minifié pour que je n'ai pas à dire à webpack d'exécuter babel dans node_modules et
- Être capable d'importer chaque classe individuelle directement à partir de mon point d'entrée au lieu d'avoir à entrer le chemin d'accès à chaque fichier
Quelle est la meilleure pratique ici? Comment les autres réalisent-ils des configurations similaires? J'ai remarqué que GlideJS a une version ESM de son package qui vous permet d'importer uniquement les choses dont vous avez besoin sans avoir à exécuter babel par exemple.
Le package en question: 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']
}
}
]
}
]
}
};
package.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"
}
}
main
attribut (point d'entrée) dans le package.json de votre bibliothèque? Enregistrez votre build. Et comment vous regroupez votre paquet lib?import { MyClass } from 'my-package/src/MyClass';
. Vous pouvez également supprimer le package de génération src pour raccourcir le chemin d'accès au fichier.Réponses:
Oui, la façon dont vous l'avez configurée consiste à importer chaque classe dans index.js, qui est ensuite transposé en un seul fichier (s'il cible ES5, ce qui est le plus courant *). Cela signifie que lorsque ce fichier est importé dans un autre fichier, il est livré dans son intégralité, avec toutes ces classes.
Si vous voulez un tremblement d'arbre approprié, vous devez éviter de le transpiler en un paquet CommonJS (ES5). Ma suggestion est de conserver les modules ES6, soit seuls, soit dans un emplacement séparé du bundle ES5. Cet article devrait vous aider à bien comprendre cela et a recommandé des instructions. Essentiellement, cela revient à définir l'environnement Babel à l'aide de preset-env (fortement recommandé si vous ne l'utilisez pas déjà!) Pour préserver la syntaxe ES6 . Voici la configuration Babel appropriée, si vous ne voulez pas transpiler vers ES5:
L'article explique comment configurer 2 bundles, chacun utilisant une syntaxe de module différente.
Il convient également de noter, et est également mentionné dans l'article, que vous pouvez définir le point d'entrée du module ES dans package.json. Cela indique à Webpack / Babel où se trouvent les modules ES6, ce qui peut être tout ce dont vous avez besoin pour votre cas d'utilisation. Il semble que la sagesse conventionnelle dit de faire:
Mais la documentation de Node l'a comme:
Si j'avais le temps, je jouerais avec cela et verrais ce qui fonctionne correctement, mais cela devrait être suffisant pour vous mettre sur la bonne voie.
* Les bundles ciblés par ES5 sont au format CommonJS, qui doit inclure tous les fichiers associés, car ES5 ne prend pas en charge les modules natifs. Cela est arrivé dans ES2015 / ES6.
la source
targets.esmodules: true
et bien que cela ait apporté des modifications au script construit, il n'a fait aucun changement quant à ce qui a été importé à la fin. L'importation d'une seule classe depuismy-package
importe toujours tout. J'ai également essayé les changements danspackage.json
(avec l'autre changement) et cela n'a rien changé non plus. Eh bien, l'ajout a entype: module
fait cassé ma version avec "Doit utiliser l'importation pour charger le module ES: /sleek-ui/webpack.config.js require () des modules ES n'est pas pris en charge." j'ai donc dû retirer ce bit. Je vais jeter un œil à l'article lié.modules: false
(pas à l'intérieurtargets
) mais cela n'a pas fonctionné non plus ... Je pense que je vais juste importer directement à partir du fichier source et continuer à exécuter babel via node_modules jusqu'à ce que nous puissions utiliser ce genre de choses nativement.import MyClass from 'my-package/myClass';
. Les lodash-es en sont un bon exemple .Il s'agit d'un cas d'utilisation valide. Le but ultime étant de le faire,
import { MyClass } from 'my-package'
mais il existe une façon plus propre de le faire.Créez un fichier d'index agrégateur dans votre fichier
my-package
. Fondamentalementmy-package/index.js
, cela devrait ressembler à ceci:Ensuite, vous pouvez le faire
import { MyClass } from 'my-package'
. Peasy facile.S'amuser!
la source