Criei um pacote NPM relativamente pequeno, composto por aproximadamente 5 classes ES6 diferentes contidas em um arquivo cada, todas elas se parecem com isso:
export default class MyClass {
// ...
}
Em seguida, configurei um ponto de entrada para o meu pacote que se parece com isso:
export { default as MyClass } from './my-class.js';
export { default as MyOtherClass } from './my-other-class.js';
Depois, executei o ponto de entrada no webpack e no babel, terminando com um index.js transpilado e minificado
Instalar e importar o pacote funciona bem, mas quando faço o seguinte no código do meu cliente:
import { MyClass } from 'my-package';
Ele não importa apenas "MyClass"; importa todo o arquivo, incluindo todas as dependências de todas as classes (algumas das minhas classes têm enormes dependências).
Imaginei que é assim que o webpack funciona quando você tenta importar partes de um pacote já empacotado? Então, eu configurei minha configuração local do webpack para executar também node_modules/my-package
através do babel e tentei:
import { MyClass } from 'my-package/src/index.js';
Mas mesmo isso importa todas as classes exportadas pelo index.js. A única coisa que parece funcionar do jeito que eu quero é se eu fizer:
import MyClass from 'my-package/src/my-class.js';
Mas eu prefiro:
- Poder importar o arquivo transpilado e minificado para que eu não precise dizer ao webpack para executar o babel dentro de node_modules e
- Ser capaz de importar cada classe individual diretamente do meu ponto de entrada, em vez de precisar digitar o caminho para cada arquivo
Qual é a melhor prática aqui? Como outras pessoas conseguem configurações semelhantes? Notei que o GlideJS possui uma versão ESM de seu pacote, que permite importar apenas o que você precisa sem precisar executar o babel por exemplo.
O pacote em questão: 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"
}
}
fonte
main
atributo (ponto de entrada) no package.json da sua lib? Verifique sua compilação. E como você está empacotando seu pacote lib?import { MyClass } from 'my-package/src/MyClass';
. Você também pode remover o pacote de compilação src para reduzir o caminho do arquivo.Respostas:
Sim, a maneira como você o configurou é importar todas as classes no index.js, que são transpiladas em um arquivo (se estiver direcionado ao ES5, o que é mais comum *). Isso significa que, quando esse arquivo é importado para outro arquivo, ele vem na sua totalidade, com todas essas classes.
Se você deseja agitar a árvore adequadamente, evite transpilar para um pacote CommonJS (ES5). Minha sugestão é manter os módulos ES6, por si só ou em um local separado do pacote ES5. Este artigo deve ajudá-lo a entender completamente isso e recomendou as instruções. Essencialmente, tudo se resume a definir o ambiente Babel usando o preset-env (altamente recomendado se você ainda não o estiver usando!) Para preservar a sintaxe do ES6 . Aqui está a configuração Babel relevante, se você não deseja transpilar para o ES5:
O artigo detalha como configurar 2 pacotes configuráveis, cada um usando uma sintaxe de módulo diferente.
Também vale a pena notar, e também é mencionado no artigo, você pode definir o ponto de entrada do módulo ES no package.json. Isso informa ao Webpack / Babel onde os módulos ES6 podem ser encontrados, o que pode ser tudo o que você precisa para o seu caso de uso. Parece que a sabedoria convencional diz para fazer:
Mas a documentação do nó tem como:
Se eu tivesse tempo, iria brincar com isso e ver o que funciona corretamente, mas isso deve ser suficiente para colocá-lo no caminho certo.
* Pacotes configuráveis direcionados ao ES5 estão no formato CommonJS, que deve incluir todos os arquivos associados, porque o ES5 não possui suporte ao módulo nativo. Isso veio no ES2015 / ES6.
fonte
targets.esmodules: true
e, embora isso tenha feito alterações no script criado, ele não fez nenhuma alteração no que foi importado no final. A importação de uma única classemy-package
ainda importa tudo. Eu também tentei as alteraçõespackage.json
(junto com as outras alterações) e isso também não mudou nada. Bem, a adiçãotype: module
realmente quebrou minha compilação com "Deve usar a importação para carregar o Módulo ES: /sleek-ui/webpack.config.js require () of modules ES não é suportado." então eu tive que remover esse pedaço. Vou dar uma olhada no artigo vinculado.modules: false
(não dentrotargets
), mas isso também não funcionou ... Acho que vou importar diretamente do arquivo de origem e continuar executando o babel através do node_modules até que possamos usar esse material nativamente.import MyClass from 'my-package/myClass';
. Um bom exemplo disso é o lodash-es .Este é um caso de uso válido. O objetivo final é fazer isso,
import { MyClass } from 'my-package'
mas há uma maneira mais limpa de fazer isso.Crie um arquivo de índice agregador no seu arquivo
my-package
. Basicamente,my-package/index.js
e deve ficar assim:Então você pode fazer
import { MyClass } from 'my-package'
. Mole-mole.Diverta-se!
fonte