如何在webpack DLL中包含npm模块?

12

我正在尝试使用 webpack(版本1.13)的DLL插件创建一个DLL包,该包包含我在各种React项目中所需的所有npm模块(即preact、preact-compat、redux、react-redux、redux-saga、recompose)。 我想通过我的商店内部的npm仓库分发包含所有这些npm模块的DLL包。几个Web应用程序应从npm repo加载DLL包并使用其中包含的模块。

在GitHub上webpack存储库中的使用DLLs in webpack示例中,alpha-DLL中包括一个名为module的模块。 module 来自示例目录中的 node_modules 目录下一个目录(dll目录)。

当我在dll-user目录中使用node build.js构建示例并查看dll-user/js/output.js文件时,此方法有效,我可以看到以下行:

/*! ***************************************************************************************** !*! delegated ../node_modules/module.js from dll-reference alpha_e0d5512587ca63cbbd71!*!************************************************************************** *************/

然而,名为module 的模块实际上并不是真正的npm模块,它只是直接位于 node_module 目录中的文件module.js。 我尝试包含一个“现实世界”的npm模块,例如 preact

在构建 dll dll-user 项目后,查看 output.js 文件,我可以看到整个preact模块的代码已包含在输出中,没有委派发生。

我该如何使其正常工作?这是webpack中的一个错误吗?

我基于webpack DLL示例在GitHub上创建了一个代码示例,展示了这个问题:https://github.com/pahund/webpack-dll-problem

2个回答

7

编辑:

最初我只是让给定的例子工作,但并没有真正了解应该如何使用所有内容。我写了这个(块下面的新内容):


好的,我认为我至少掌握了一部分内容。 我会告诉你如何使你的示例程序工作。

有两种方法可以使其工作:

  1. 包含文件夹即顶层的package.json(和node_modules,如果必要的话)中删除preact。现在你只有dll文件夹中的preact
    然后在dll-user文件夹中的example.js中更改require调用为
    require("../dll/node_modules/preact")
    这应该有效,但不完全是我们想要的。

  2. 现在反过来。从dll文件夹中删除preact,但仅将其安装到包含文件夹中。
    运行两个构建脚本,查看output.js是否按照应有的委托进行,包括preact


新:

好的,经过更多的探索,我认为它是这样工作的。(由于我们彼此相识并且有点共同合作,所以可以用较少的词语,但是如果我在细节上更加明确,我认为这也可能会帮助其他人,所以请耐心等待。)

初步说明:我假设您想创建一个dll文件,您可以通过npm将其安装到项目中,并通过单独的脚本标签包含在HTML中。该脚本在执行时创建一个全局变量,公开一个函数,该函数又被您的应用程序脚本用于解决依赖关系。 此外,我假设您已经设置了一个dll捆绑目录,其中只有一个package.json和已安装的webpack。

首先,您需要创建一个像这样的webpack.config.js

var webpack = require("webpack");
var path = require("path");

module.exports= {
  entry: ["preact"], // put here every module that goes into the dll
  output: {
    path: __dirname,
    filename: "index.js",
    library: "[name]_[hash]"
  },
  plugins: [
    new webpack.DllPlugin({
      path: path.join(__dirname, "[name]-manifest.json"),
      name: "[name]_[hash]" // (keep consistent with output.library)
    })
  ]
};

现在使用以下代码创建捆绑包及其清单:
$ webpack

dll项目文件夹的结构现在是:

dll-project
|_ node_modules
| |_ preact
|_ main.js
|_ main-mainifest.json
|_ package.json
|_ webpack.config.js

现在你已经将这个包安装到另一个项目中,即你的应用程序:
app
|_ node_modules
| |_ dll-project
|_ index.js
|_ package.json
|_ webpack.config.js

This webpack.config.js 看起来像(或类似于)这样:

var webpack = require("webpack");

module.exports= {
  entry: "./index.js",
  output: {
    path: __dirname,
    filename: "app.js"
  },
  plugins: [
    new webpack.DllReferencePlugin({
      scope: mydll,
      manifest: require("./node_modules/dll-project/main-manifest.json")
    })
  ]
};

在您的应用程序代码中,即index.js中,您需要以以下方式引入dll捆绑包中的模块:
var React = require("mydll/node_modules/preact/dist/preact");

如果您运行webpack -d,则会在生成的app.js中看到类似以下内容的东西:
/* 1 */
/*!***************************************************************************************************!*\
  !*** delegated ./node_modules/preact/dist/preact.js from dll-reference main_2057857de340fdcfd8aa ***!
  \***************************************************************************************************/

有人可能会问:“为什么我不能像使用require("preact")那样使用我的标准requires呢?”答案是:你可以,但是。但是在这种情况下,你必须在你的dll bundle中安装所有这些依赖项,并且在你的应用程序中也要安装它们。因为在这种情况下,你将使用“映射模式”而不是“作用域模式”(参见Webpack Docs)。

在作用域模式下,你必须明确地require相对于清单的模块路径。好处是:你不必在你的应用程序中安装模块(并将其作为package.json中的依赖项)。

在映射模式下,你可以像通常一样需要模块(就像它已经安装在你的应用程序的node_modules中一样),但你也必须在使用app的dll中安装它。这是因为Webpack将首先评估require调用,然后意识到相同的模块也在dll bundle中,因此只渲染一个别名(“委托...”)到输出中。


现在我认为这两种模式都有用例。如果你只是构建一个本地应用程序dll来加速构建,那么映射模式很酷。在这种情况下,您将安装和保存所有进入dll的依赖项。但是,如果您想将dll捆绑成可安装模块并在应用程序之间共享它 - 而且您不想在每个这些应用程序中跟踪dll中的所有模块 - 您很可能希望使用作用域模式,付出更多冗长的require调用的代价。


1
谢谢,我会查看你的解决方案并回复你。有趣的是,Bilbasen 的团队正在做我计划中的事情,并且他们成功了。 - Patrick Hund
1
这解决了三天的困惑。谢谢。我希望DllReferencePlugin能够修改为盲目接受manifest.json文件中的内容。当存在于清单中时,我不认为webpack需要解析require。 - Ian G

1
你可以尝试这种方式;
new webpack.DllReferencePlugin({
  context: process.cwd(), // Important
  manifest: manifest.json
}),

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接