Я создал сравнительно небольшой пакет NPM, состоящий примерно из 5 различных классов ES6, содержащихся в одном файле, каждый из которых выглядит примерно так:
export default class MyClass {
// ...
}
Затем я установил точку входа для моего пакета, которая выглядит следующим образом:
export { default as MyClass } from './my-class.js';
export { default as MyOtherClass } from './my-other-class.js';
Затем я пропустил точку входа через webpack и babel, получив в итоге прозрачный и минимизированный index.js.
Установка и импорт пакета работает нормально, но когда я делаю следующее из моего клиентского кода:
import { MyClass } from 'my-package';
Он не просто импортирует «MyClass», он импортирует весь файл, включая все зависимости каждого класса (некоторые из моих классов имеют огромные зависимости).
Я понял, как работает веб-пакет, когда вы пытаетесь импортировать части уже упакованного пакета? Поэтому я настроил свой локальный веб-пакет для работы node_modules/my-package
через babel, а затем попытался:
import { MyClass } from 'my-package/src/index.js';
Но даже это импортирует каждый класс, экспортируемый index.js. Единственное, что, кажется, работает так, как я хочу, это если я это сделаю:
import MyClass from 'my-package/src/my-class.js';
Но я бы предпочел:
- Уметь импортировать перенесенный и свернутый файл, чтобы мне не пришлось указывать webpack запускать babel внутри node_modules и
- Иметь возможность импортировать каждый отдельный класс непосредственно из моей точки входа вместо того, чтобы вводить путь к каждому файлу
Какова лучшая практика здесь? Как другие достигают подобных установок? Я заметил, что GlideJS имеет версию ESM своего пакета, которая позволяет вам импортировать только те вещи, которые вам нужны, без необходимости, например, запускать babel.
Рассматриваемый пакет: 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
атрибут (точки входа) в package.json вашей библиотеки? Проверьте в вашей сборке. А как вы упаковываете свой пакет lib?import { MyClass } from 'my-package/src/MyClass';
. Вы также можете удалить сборку сборки src, чтобы сократить путь к файлу.Ответы:
Да, вы настроили его, импортируя каждый класс в index.js, который затем переносится в один файл (если он нацелен на ES5, что наиболее распространено *). Это означает, что когда этот файл импортируется в другой файл, он приходит полностью со всеми этими классами.
Если вы хотите правильно потрясти дерево, вам следует избегать его переноса в пакет CommonJS (ES5). Мое предложение состоит в том, чтобы хранить модули ES6 либо отдельно, либо отдельно от комплекта ES5. Эта статья должна помочь вам полностью понять это и имеет рекомендованные инструкции. По сути, это сводится к настройке среды Babel с использованием preset-env (настоятельно рекомендуется, если вы ее еще не используете!) Для сохранения синтаксиса ES6 . Вот соответствующая конфигурация Babel, если вы не хотите переходить на ES5:
В статье подробно описано, как настроить 2 пакета, каждый из которых использует свой синтаксис модуля.
Также стоит отметить, что, как упоминается в статье, вы можете установить точку входа модуля ES в package.json. Это говорит Webpack / Babel, где можно найти модули ES6, что может быть всем, что вам нужно для вашего случая использования. Кажется, общепринятая мудрость гласит:
Но документация Node имеет это как:
Если бы у меня было время, я бы поиграл с этим и увидел, что работает правильно, но этого должно быть достаточно, чтобы вы выбрали правильный путь.
* Пакеты, ориентированные на ES5, имеют формат CommonJS, который должен включать все связанные файлы, поскольку ES5 не имеет встроенной поддержки модулей. Это пришло в ES2015 / ES6.
источник
targets.esmodules: true
и хотя он внес изменения во встроенный скрипт, он не изменил то, что было импортировано в конце. Импорт одного отдельного класса из по-my-package
прежнему импортирует все. Я также попробовал изменения вpackage.json
(наряду с другими изменениями), и это тоже ничего не изменило. Что ж, добавлениеtype: module
фактически сломало мою сборку: «Для загрузки модуля ES необходимо использовать импорт: /sleek-ui/webpack.config.js require () модулей ES не поддерживается». поэтому мне пришлось удалить этот бит. Я посмотрю на связанную статью.modules: false
(не внутриtargets
), но это тоже не сработало ... Я думаю, что я просто импортирую напрямую из исходного файла и продолжу запускать babel через node_modules, пока мы не сможем использовать этот материал изначально.import MyClass from 'my-package/myClass';
. Хорошим примером этого репо является lodash-es .Это действительный вариант использования. Конечная цель состоит в том, чтобы сделать это,
import { MyClass } from 'my-package'
но есть более чистый способ сделать это.Создайте индексный файл агрегатора в вашем
my-package
. В основномmy-package/index.js
и это должно выглядеть так:Тогда вы можете сделать
import { MyClass } from 'my-package'
. Очень просто.Радоваться, веселиться!
источник