Webpack有两个常见的块:一个是导出的,一个是本地的

时间:2016-02-23 18:16:19

标签: javascript webpack

我想在多页面应用程序中使用Webpack,以便将一些预先确定的依赖项捆绑到“供应商”块中,并将其余的依赖项捆绑到“commons”块中。

例如,假设有两个入口点(有效地表示每个页面的不同页面),pageA.jspageB.js包含此代码(在EC6中,通过Babel处理),后跟自己的代码:< / p>

import $ from 'jquery';
require('bootstrap/dist/css/bootstrap.css');
import angular from 'angular';
import uitree from 'angular-ui-tree';

我希望将jQuery和Bootstrap捆绑到一个“供应商”块中,然后将其余的(无论是什么)捆绑到“commons”块中。

目标是:

  • 我希望能够拥有另一个能够依赖同一个供应商块的独立构建,而不需要重新包含供应商库(我会明确地声明这组供应商库,以便制作它可用于任何需要它的子构建。)
  • 每次我更改页面脚本时,我也不想重新处理供应商块。

以下是我尝试过的配置:

module.exports = {
    entry : {
        "vendor" : [ "jquery", "bootstrap" ],
        "pageA" : "./src/pageA.js",
        "pageB" : "./src/pageB.js"
    },
    output : {
        path : path.join(__dirname, "./dest"),
        filename : "[name].chunk.js"
    },
    module : {
        loaders : [ {
            test : /bootstrap\/js\//,
            loader : 'imports?jQuery=jquery'
        },
        /* ... Some modules for angular and CSS processing ... */

        {
            test : /\.js?$/,
            include : [ path.resolve(__dirname, "./src") ],
            loader : 'babel',
            query : {
                presets : [ 'es2015' ]
            }
        }
        /* ... Some other settings for the fonts ... */ ]
    },
    plugins : [
        new webpack.ProvidePlugin({
            $ : "jquery",
            jQuery : "jquery"
        }),
        new webpack.optimize.UglifyJsPlugin({
            sourceMap : false,
            mangle : false,
            compress : false
        }),
        new CommonsChunkPlugin({
            name : "vendor",
            minChunks : Infinity
        }),
        new CommonsChunkPlugin({
            name : "commons",
            minChunks : 2
        })
    ]
};

通过上面的配置,我可以根据需要在vendor.chunk.js中获取jQuery和Bootstrap,但commons.chunk.js文件几乎为空,pageA.js和{pageB.js常用的所有内容然后将{1}}放入pageA.chunk.jspageB.chunk.js(有效复制该代码)。

如果我交换最后两个插件的顺序,commons.chunk.js现在几乎包含所有内容(除非实际上特定于pageA.jspageB.js),vendor.chunk.js几乎是空:

plugins : [
    // ...,
    new CommonsChunkPlugin({
        name : "commons",
        minChunks : 2
    }),
    new CommonsChunkPlugin({
        name : "vendor",
        minChunks : Infinity
    })
]

是否有办法将预定义的库列表(例如[ "jquery", "jquery-ui", "bootstrap" ])捆绑到一个特定的块中(以完全独立的脚本可以使用的方式),并且还有另一个常见的块其他是在入口点之间常用的吗?

所有这一切的目的是能够在以后为另一个页面构建完全独立的代码片段,并告诉它不需要重新捆绑这些预定义的库。

这是一个代表我想要实现的目标的图表:

Dependencies Diagram

然后我将使用生成的脚本,如下页A:

<script src="vendor.js"></script>
<script src="common.js"></script>
<script src="pageA.chunk.js"></script>

在页面C(完全独立于页面A和B构建):

<script src="vendor.js"></script>
<script src="common2.js"></script>
<script src="pageC.chunk.js"></script>

(我正在使用Webpack 1.12.14。)

我尝试了the only answer so far中建议的解决方案。虽然这使得确实可以将供应商块与公共块分开,但是由两个单独的构建制成的供应商块(具有相同的定义)通常不能在彼此之间交换。这样就无法在两个版本中仅使用其中一个供应商块(即使它们几乎相同)。

2 个答案:

答案 0 :(得分:10)

我正在做类似的事情。我通过这种配置观察了你想要的行为:

const entryPath = path.resolve(__dirname, "src", "modules"),
    entryPoints = {
        vendor: ["babel-polyfill", "react", "react-dom", "react-pure-render", "react-simpletabs", "react-redux", "redux", "redux-thunk"],
        a: entryPath + "/a.js",
        b: entryPath + "/b.js",
        c: entryPath + "/c.js",
        d: entryPath + "/d.js",
        ...
    }, plugins = [
        new CommonsChunkPlugin({
            name: "commons",
            filename: "commons.bundle.js",
            minChunks: 2,
            chunks: Object.keys(entryPoints).filter(key => key !== "vendor")
        }),
        new CommonsChunkPlugin("vendor", "vendor.bundle.js"),
        new ExtractTextPlugin("[name].bundle.css", {
            //allChunks: true
        })
    ];

所以上面这个代码留在b.bundle.js中仍然有一些React和其他React库的导入。在我将“fixed-data-table”添加到供应商列表后,消失了,唯一的反应源代码是在vendor.bundle.js中我认为这就是你要找的东西? (最后,供应商列表中未列出的每个供应商最终都在每个自己的module.bundle.js或commons.bundle.js中,如果它在多个包中重复使用的话)

此致 纳斯

答案 1 :(得分:2)

至于您的请求能够使用来自另一个构建的bundle中的一个webpack构建中创建的供应商块,我发现这样做的唯一方法是expose-loader和{{1 }}

就我而言,我成功地将它用于将jQuery(和Bootstrap)捆绑到一个&#34; common.js&#34;在一个构建中,然后在属于另一个构建的模块中使用该jQuery,如下所示:

1。从build A chunk

公开jQuery
externals

2。在构建B模块中使用jQuery

module: {
  loaders: [
    {
      // export jQuery globals for other modules to use as externals
      test: require.resolve('jquery'),
      loader: 'expose?$!expose?jQuery'
    }
  ]
}

当然,这样做的缺点是你通过使用手动管理的全局变量在两组bundle之间进行桥接,你可能已经开始使用webpack来避免: - )

但是,我现在还不知道其他任何方式,因为每个webpack构建都会创建自己的名称空间&#34; private&#34;内部ID用于引用模块,不保证稳定性或全局唯一性。