Cách xuất nhiều mô-đun ES6 từ một gói NPM


16

Tôi đã xây dựng một gói NPM tương đối nhỏ bao gồm khoảng 5 lớp ES6 khác nhau được chứa trong một tệp, mỗi tệp trông khá giống nhau như sau:

export default class MyClass {
    // ...
}

Sau đó, tôi đã thiết lập một điểm vào cho gói của mình trông như thế này:

export { default as MyClass } from './my-class.js';
export { default as MyOtherClass } from './my-other-class.js';

Sau đó, tôi đã chạy điểm vào thông qua webpack và babel kết thúc với một index.js được dịch mã và rút gọn

Cài đặt và nhập gói hoạt động tốt, nhưng khi tôi thực hiện các thao tác sau từ mã máy khách của mình:

import { MyClass } from 'my-package';

Nó không chỉ nhập "MyClass" mà nó nhập toàn bộ tệp bao gồm tất cả các phụ thuộc của mỗi lớp (một số lớp của tôi có phụ thuộc rất lớn).

Tôi hình dung đây là cách webpack hoạt động khi bạn cố gắng nhập các phần của gói đã được gói? Vì vậy, tôi đã thiết lập cấu hình webpack cục bộ của mình để chạy node_modules/my-packagequa babel và sau đó thử:

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

Nhưng ngay cả điều này cũng nhập mọi lớp đơn được xuất bởi index.js. Điều duy nhất có vẻ hoạt động theo cách tôi muốn là nếu tôi làm:

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

Nhưng tôi muốn nói nhiều hơn:

  1. Có thể nhập tệp được sao chép và rút gọn để tôi không phải yêu cầu webpack chạy babel bên trong node_modules và
  2. Có thể nhập từng lớp riêng lẻ trực tiếp từ điểm vào của tôi thay vì phải nhập đường dẫn đến từng tệp

Thực hành tốt nhất ở đây là gì? Làm thế nào để những người khác đạt được các thiết lập tương tự? Tôi đã nhận thấy GlideJS có phiên bản ESM của gói cho phép bạn chỉ nhập những thứ bạn cần mà không phải chạy babel qua nó.

Gói trong câu hỏi: 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']
                        }
                    }
                ]
            }
        ]
    }
};

pack.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
Bạn đã thêm thuộc tính main(điểm vào) trong gói.j.j của lib chưa? Kiểm tra bản dựng của bạn. Và làm thế nào bạn đang gói gói lib của bạn?
Abhishek

Thuộc tính chính của gói.json là hướng đến điểm vào tới mô-đun mà gói.json đang mô tả. Trong ứng dụng Node.js, khi mô-đun được gọi thông qua câu lệnh yêu cầu, xuất khẩu của mô-đun từ tệp có tên trong thuộc tính chính sẽ là những gì được trả về cho ứng dụng Node.js.
Abhishek

Có, thuộc tính chính trỏ đến index.js của tôi, xuất tất cả các lớp khác. Tôi đang gói tệp chính / index.js bằng cách sử dụng webpack và babel. Tất cả đều được giải thích trong câu hỏi.
powerbuoy

điều này có thể giúp bạn - danielberndt.net/blog/2018/...
Abhishek

Bạn cũng có thể tại triển khai bản dựng của họ - github.com/mui-org/m vật liệu - ui / blog / master / pack / m Material - ui / Kẻ Để có kích thước bản dựng ngắn hơn, tốt hơn nên làm import { MyClass } from 'my-package/src/MyClass';. Bạn cũng có thể loại bỏ bao bì xây dựng src để rút ngắn đường dẫn tệp.
Abhishek

Câu trả lời:


1

Tôi hình dung đây là cách webpack hoạt động khi bạn cố gắng nhập các phần của gói đã được gói?

Đúng, cách bạn đã thiết lập nó là nhập mọi lớp trong index.js, sau đó được dịch mã thành một tệp (nếu nó nhắm mục tiêu ES5, phổ biến nhất *). Điều này có nghĩa là khi tệp đó được nhập vào một tệp khác, nó có toàn bộ, với tất cả các lớp đó.

Nếu bạn muốn rung cây thích hợp, bạn nên tránh chuyển nó thành một gói CommonJS (ES5). Đề nghị của tôi là giữ các mô-đun ES6, một mình hoặc ở một vị trí riêng biệt với gói ES5. Bài viết này sẽ giúp bạn hiểu đầy đủ điều này và có hướng dẫn khuyến nghị. Về cơ bản, nó tập trung vào việc thiết lập môi trường Babel bằng preset-env (rất khuyến khích nếu bạn chưa sử dụng nó!) Để duy trì cú pháp ES6 . Đây là cấu hình Babel có liên quan, nếu bạn không muốn chuyển sang ES5:

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

Bài viết chi tiết cách thiết lập 2 gói, mỗi gói sử dụng một cú pháp mô-đun khác nhau.

Cũng đáng chú ý và cũng là một loại được đề cập trong bài viết, bạn có thể đặt điểm nhập mô-đun ES trong pack.json. Điều đó cho Webpack / Babel biết nơi có thể tìm thấy các mô-đun ES6, đây có thể là tất cả những gì bạn cần cho trường hợp sử dụng của mình. Có vẻ như trí tuệ thông thường nói phải làm:

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

Nhưng tài liệu Node có nó như:

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

Nếu tôi có thời gian tôi sẽ chơi xung quanh với cái này và xem cái nào hoạt động chính xác, nhưng điều này là đủ để đưa bạn đi đúng hướng.


* Các gói nhắm mục tiêu ES5 có định dạng CommonJS, bao gồm tất cả các tệp được liên kết, vì ES5 không có hỗ trợ mô-đun gốc. Điều đó đến trong ES2015 / ES6.


Tôi đã thử thêm targets.esmodules: truevà trong khi điều đó đã thay đổi tập lệnh được xây dựng, nó không tạo ra thay đổi nào so với nội dung được nhập vào cuối cùng. Nhập một lớp duy nhất từ my-packagevẫn nhập mọi thứ. Tôi cũng đã thử các thay đổi trong package.json(cùng với các thay đổi khác) và điều đó cũng không thay đổi gì cả. Chà, việc thêm type: modulethực sự đã phá vỡ bản dựng của tôi với "Phải sử dụng nhập để tải Mô-đun ES: /sleek-ui/webpack.config.js yêu cầu () các mô-đun ES không được hỗ trợ." Vì vậy, tôi đã phải loại bỏ bit đó. Tôi sẽ xem xét bài viết được liên kết.
powerbuoy

Ok, bài báo thực sự đã bảo tôi đặt modules: false(không phải bên trong targets) nhưng nó cũng không hoạt động ... Tôi nghĩ rằng tôi sẽ chỉ nhập trực tiếp từ tệp nguồn và tiếp tục chạy babel qua node_modules cho đến khi chúng ta có thể sử dụng công cụ này một cách tự nhiên.
powerbuoy

@powerbuoy Nhập từ tệp nguồn hoạt động. Có thể nó không rõ ràng từ bài đăng của tôi và nếu đó là trường hợp tôi có thể chỉnh sửa nó, nhưng bạn chỉ muốn nhập lớp như thế nào import MyClass from 'my-package/myClass';. Một ví dụ repo tốt về điều này là lodash-es .
CaitlinWeb

-1

Đây là một trường hợp sử dụng hợp lệ. Mục tiêu cuối cùng là làm điều này import { MyClass } from 'my-package'nhưng có một cách sạch hơn để làm điều này.

Tạo một tệp chỉ mục tổng hợp trong của bạn my-package. Về cơ bản my-package/index.jsvà nó sẽ trông như thế này:

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

export { MyClass, MyOtherClass }

Sau đó bạn có thể làm import { MyClass } from 'my-package' . Dễ như ăn bánh.

Chúc vui vẻ!


Đây chính xác là những gì tôi đã làm, điều mà tôi nghĩ là khá rõ ràng trong câu hỏi.
powerbuoy
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.