如何从一个NPM包中导出多个ES6模块


16

我构建了一个相对较小的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”,还导入整个文件,包括每个类的所有依赖关系(我的某些类具有很大的依赖关系)。

当您尝试导入已捆绑的软件包的一部分时,我想到了webpack是如何工作的?所以我也将我的本地webpack配置设置为也node_modules/my-package通过babel 运行,然后尝试:

import { MyClass } from 'my-package/src/index.js';

但是即使这样,它也会导入index.js导出的每个类。看来我想要的唯一运作方式是:

import MyClass from 'my-package/src/my-class.js';

但我宁愿:

  1. 能够导入转译和缩小的文件,这样我就不必告诉webpack在node_modules和
  2. 能够直接从我的入口点导入每个单独的类,而不必输入每个文件的路径

最佳做法是什么?其他人如何实现类似的设置?我注意到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"
  }
}

1
您是否main在lib的package.json中添加了(入口点)属性?签入您的版本。以及如何捆绑您的lib软件包?
阿布舍克

package.json的主要属性是指向package.json描述的模块入口点的方向。在Node.js应用程序中,当通过require语句调用模块时,模块从main属性中命名的文件中导出的内容将返回给Node.js应用程序。
Abhishek,

是的,主要属性指向导出所有其他类的index.js。我正在使用webpack和babel捆绑main / index.js文件。问题中都有解释。
powerbuoy

这可能会帮助你- danielberndt.net/blog/2018/...
阿布舍克

您也可以在其构建实现中进行访问-github.com/mui-org/material-ui/blob/master/packages/material-ui / ... 为了缩短构建大小,最好这样做import { MyClass } from 'my-package/src/MyClass';。您也可以删除src build打包以缩短文件路径。
Abhishek

Answers:


1

当您尝试导入已捆绑的软件包的一部分时,我想到了webpack是如何工作的?

是的,设置方法是将index.js中的每个类导入,然后将其转换为一个文件(如果它的目标是ES5,这是最常见的*)。这意味着,当将该文件导入另一个文件时,它将全部包含所有这些类。

如果要进行适当的摇树,则应避免将其转换为CommonJS(ES5)捆绑软件。我的建议是单独保留ES6模块,或者将其与ES5软件包分开放置。本文应帮助您完全理解这一点,并建议使用指导。从本质上讲,它可以归结为使用preset-env设置Babel环境(如果您尚未使用它,则强烈建议!)以保留ES6语法。如果您不想移植到ES5,这是相关的Babel配置:

{
  "presets": [
    [
      "@babel/preset-env",
      {
        "targets": {
          "esmodules": true
        }
      }
    ]
  ]
}

本文详细介绍了如何设置2个捆绑包,每个捆绑包使用不同的模块语法。

同样值得注意的是,您也可以在package.json中设置ES模块入口点,并且在本文中也提到了这一点。这就告诉Webpack / Babel可以在哪里找到ES6模块,这可能是您使用案例所需的全部。似乎传统的智慧说:

{
  "main": "dist/sleek-ui.js",
  "module": "src/main.js"
}

但是Node文档将其作为:

{
  "type": "module",
  "main": "dist/sleek-ui.js",
  "exports": {
    ".": "dist/sleek-ui.js",
    "./module": "src/main.js"
  }
}

如果我有时间,我会试着解决这个问题,看看哪个工作正常,但这足以使您走上正确的道路。


* 面向ES5的捆绑包采用CommonJS格式,该文件必须包含所有相关文件,因为ES5不支持本机模块。那是ES2015 / ES6。


我尝试添加targets.esmodules: true,虽然对生成的脚本进行了更改,但最终导入的内容没有任何变化。从一个类导入一个类my-package仍然会导入所有内容。我还尝试了package.json(以及其他更改)中的更改,但也没有更改任何内容。好吧,添加type: module实际上使我的构建中断了,“必须使用导入来加载ES模块:不支持ES模块的/sleek-ui/webpack.config.js require()”。所以我不得不去掉那一点。我将看一下链接的文章。
powerbuoy

好的,所以这篇文章实际上告诉我要进行设置modules: false(而不是inside targets),但是那也不起作用……我想我将直接从源文件中导入并继续通过node_modules运行babel,直到我们可以本地使用此东西为止。
powerbuoy

@powerbuoy从源文件导入有效。也许从我的帖子中还不清楚,如果可以的话,我可以对其进行编辑,但是您只想导入此类import MyClass from 'my-package/myClass';lodash-es是一个很好的回购示例。
CaitlinWeb

-1

这是一个有效的用例。最终目标是做到这一点,import { MyClass } from 'my-package'但是有一种更干净的方法可以做到这一点。

在中创建一个聚合器索引文件my-package。基本上my-package/index.js,它应该像这样:

import MyClass from './my-class.js'
import MyOtherClass from './my-other-class.js'

export { MyClass, MyOtherClass }

那你就可以做import { MyClass } from 'my-package'。十分简单。

玩得开心!


这正是我已经在做的,我认为这个问题很清楚。
powerbuoy
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.