如何使用一些可选模块构建多包节点模块

Posted

技术标签:

【中文标题】如何使用一些可选模块构建多包节点模块【英文标题】:How to build a multi package node module with some optional modules 【发布时间】:2021-01-29 19:16:01 【问题描述】:

几天以来,我一直在尝试构建一个节点模块,该模块将被 React 应用程序使用。

今天我的模块被打包成一个用 webpack 打包的大 javascript 文件。 此节点模块的某些部分是可选的,仅当我们想要使用某些功能(通过配置激活)时才需要。为了避免加载不必要的代码部分,我首先尝试按照 webpack 的解释使用 chunkingdynamic import 但这并没有工作:在dist/ 文件夹中创建和打包块,但是当从反应应用程序调用时,我从未成功在节点模块中运行动态导入。应用程序抱怨无法从应用程序加载块。这对我来说很有意义,因为这个 webpack 功能更多地是为了动态加载应用程序的一部分,而不是作为节点模块依赖项按需加载代码的内部机制(但我可能是错的)。

我查看了其他项目,如 babelreact-router,其中模块使用 lernayarn 拆分为多个包包。所以我尝试用 lerna 和不同的包来构建库:

my-library
  core/
    src/
      index.js
  another-package/
    src/
      index.js

我希望 core 中的 index.js 文件仅在需要且仅在安装了节点模块 @my-library/another-package 的情况下才能从 index.jsanother-package 调用方法。但我从来没有找到解决方案。 是否可以通过ES5/ES6webpack/lerna 实现这一目标,还是我采取了错误的方法?

10 月 27 日更新

所以经过几次测试,我能够使用带有纯 html/JS (https://github.com/PixelDuck/lerna-webpack/blob/main/a-react-app/src/client/test.html) 的 Aram 解决方案,但该解决方案不适用于带有 webpack https://github.com/PixelDuck/lerna-webpack/blob/main/a-react-app/src/client/App.js 的 React 应用程序包。

代码可在此处获得:https://github.com/PixelDuck/lerna-webpack。

打开终端到my-lerna-library 并运行 yarn install yarn link:all,这将为每个包创建符号链接 `yarn dev',这将创建包并监听变化

然后打开一个新终端到文件夹a-react-appyarn install yarn link "my-lerna-library" yarn link "@my-lerna-library/another-package" `纱线开发`

将在http://0.0.0.0:3000 上打开一个页面,您将看到模块@my-lerna-library/another-package 未找到。

如果你打开http://0.0.0.0:5000/test.htmlplainJS 测试,一切看起来都很好。

似乎问题出在 react 应用程序的 webpack 方面,因为在调试应用程序时,我可以看到核心包正在寻找库名称 my_lerna_library__WEBPACK_IMPORTED_MODULE_3__,这不是 webpack 在加载另一个时使用的库名称包_my_lerna_library_another_package__WEBPACK_IMPORTED_MODULE_2___default

__webpack_require__.r(__webpack_exports__);
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "./node_modules/react/index.js");
/* harmony import */ var _App_css__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./App.css */ "./src/client/App.css");
/* harmony import */ var _App_css__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_App_css__WEBPACK_IMPORTED_MODULE_1__);
/* harmony import */ var _my_lerna_library_another_package__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @my-lerna-library/another-package */ "../my-lerna-library/packages/another-package/dist/index.bundle.js");
/* harmony import */ var _my_lerna_library_another_package__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(_my_lerna_library_another_package__WEBPACK_IMPORTED_MODULE_2__);
/* harmony import */ var my_lerna_library__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! my-lerna-library */ "../my-lerna-library/packages/core/dist/index.bundle.js");
/* harmony import */ var my_lerna_library__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(my_lerna_library__WEBPACK_IMPORTED_MODULE_3__);

【问题讨论】:

【参考方案1】:

如果您需要一个带有可选依赖项的包,您可以创建一个核心包以及几个功能包(它们是不是 甚至列在 peerDependencies 中)。您可以在optionalDependencies 中明确列出这些功能包。

此外,您的核心包的设计应使其不需要功能包,但如果已安装,则可以正确使用它们。比如这样https://***.com/a/50841764/14451484。

【讨论】:

您好,您的解决方案听起来很有希望,但我无法让它发挥作用。更改后,核心库中的方法总是返回此错误:``` 错误:在 webpackEmptyContext at loadOptionalPackage at Object../src/index.js 上找不到模块 '@my-lerna-library/another-package' b>nested_webpack_require_5300 在 index.bundle.js:19 在 index.bundle.js:192 在 webpackUniversalModuleDefinition 在 Object../node_modules/my-lerna-library/dist/index.bundle.js 在 webpack_require (引导程序:21)``` 注意 optionalDependencies 让 webpack dev 卡在核心包上,所以我不得不使用optionalPeerDependencies 如果你有时间看看的话,我已经在 github 上用一些新闻和一个测试用例更新了我的问题.....【参考方案2】:

在你的 my-lerna-library > 包中:-

(1) another-package package.json 文件替换为这段代码


  "name": "@my-lerna-library/another-package",
  "private": true,
  "version": "1.0.0",
  "scripts": 
    "dev": "webpack --watch --devtool inline-source-map --mode development",
    "build": "webpack --mode production"
  ,
  "dependencies": 
    "@my-lerna-library/core": "1.0.0"
  

(2) 核心 package.json 文件替换为这段代码


  "name": "@my-lerna-library/core",
  "private": true,
  "version": "1.0.0",
  "scripts": 
    "dev": "webpack --watch --devtool inline-source-map --mode development",
    "build": "webpack --mode production"
  

和 my-lerna-library package.json 文件替换这样的工作区,

"workspaces": 
    "packages": [
      "packages/**"
    ]
,

然后运行命令“yarn run dev”。我觉得这对你有用!!

【讨论】:

嗨。谢谢你的时间。我已经尝试过了,但它不起作用。在为核心生成的代码中,我可以看到 ``` anotherPackage = __webpack_require__(Object(function webpackMissingModule() var e = new Error("Cannot find module '@my-lerna-library/another-package'"); e。代码 = 'MODULE_NOT_FOUND'; 抛出 e; ())); ``` 所以这行不通。将核心 another-package 定义为 optionalPeerDependencies 并在 webpack 配置中声明为 external 修复代码:``` anotherPackage = __webpack_require__(/*!@my-lerna-library/another-package */ "@my-lerna-library/another -package");``` Web 应用程序上仍然存在问题: ../my-lerna-library/packages/core/dist/index.bundle.js 中的警告 6:13-57 [1] 未找到模块:错误:无法解析“/Users/olmartin/dev/js/lerna-webpack/my-lerna-library/packages/core/dist”中的“@my-lerna-library/another-package”检查分支@987654321 @ 我认为问题不在于库方面,而在于 webapp 方面,我无法在范围内导入依赖项并使核心库使用 require() 查看它。【参考方案3】:

我终于能够实现我想要的。 代码在这里:https://github.com/PixelDuck/lerna-webpack

所以想法是将另一个包 webpack 配置设置为输出库为“全局”并在核心包上,查看这个全局变量

function isMyLernaLibraryAnotherPackageDefined() 
  return typeof myLernaLibraryAnotherPackage !== 'undefined';

testFromAnotherPackage() 
  if (isMyLernaLibraryAnotherPackageDefined())
    return new myLernaLibraryAnotherPackage.AnotherClass().test();

现在在 react 应用程序上,如果我正在导入 import '@my-lerna-library/another-package';then 消息和 svg 会显示。 如果我正在评论这一行,则找不到模块并且没有显示任何内容

【讨论】:

以上是关于如何使用一些可选模块构建多包节点模块的主要内容,如果未能解决你的问题,请参考以下文章

删除不必要的节点模块

Drupal 模块设置页面构建

如何从节点模块中的@types 保存类型

Node.js:如何创建付费节点模块?

如何在 laravel 5 中发布/使用节点模块?

如何在 BigQuery 中构建模块化查询?