Webpack с двумя общими кусками: один экспортированный, один локальный
Я хотел бы использовать Webpack в многостраничном приложении таким образом, чтобы некоторые заранее определенные зависимости были объединены в блок "vendor", а остальные зависимости были объединены в кусок "commons".
Например, если предположить, что две точки входа (фактически представляющие разные страницы каждый), pageA.js
и pageB.js
содержат оба этих кода (в EC6, обработанных через Babel), а затем их собственный код:
import $ from 'jquery';
require('bootstrap/dist/css/bootstrap.css');
import angular from 'angular';
import uitree from 'angular-ui-tree';
Я хотел бы, чтобы jQuery и Bootstrap были добавлены в блок "vendor", а остальные (что бы это ни было) были добавлены в кусок "commons".
Цели:
- Я хотел бы иметь еще одну отдельную сборку, которая могла бы опираться на тот же кусок поставщика, без необходимости повторного включения библиотек поставщиков (я бы прямо объявлял, что набор библиотек поставщиков, чтобы сделать это доступный для любой подстроки, которая ему нужна).
- Мне также хотелось бы не перерабатывать кусок поставщика каждый раз, когда я делаю изменения на странице script.
Вот конфигурация, которую я пробовал:
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
})
]
};
С приведенной выше конфигурацией я получаю jQuery и Bootstrap в vendor.chunk.js
, если требуется, но файл commons.chunk.js
почти пуст, все остальные, что обычно используется pageA.js
и pageB.js
, затем помещаются в pageA.chunk.js
и pageB.chunk.js
(эффективно дублируя этот код).
Если я поменяю порядок двух последних плагинов, commons.chunk.js
теперь содержит почти все (если только то, что действительно специфично для pageA.js
и pageB.js
), а vendor.chunk.js
почти пусто:
plugins : [
// ...,
new CommonsChunkPlugin({
name : "commons",
minChunks : 2
}),
new CommonsChunkPlugin({
name : "vendor",
minChunks : Infinity
})
]
Есть ли способ связать предварительно определенный список библиотек (например, [ "jquery", "jquery-ui", "bootstrap" ]
в один конкретный фрагмент (таким образом, чтобы он мог использоваться полностью независимыми скриптами), а также иметь еще один общий фрагмент, обычно используется между точками входа?
Цель всего этого заключалась бы в том, чтобы создать полностью отдельный фрагмент кода для другой страницы позже и сказать, что ему не нужно повторно связывать эти предварительно определенные библиотеки.
Вот диаграмма, показывающая, что я пытаюсь достичь:
![Диаграмма зависимостей]()
Затем я использовал сгенерированные скрипты, как показано ниже на странице 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.)
Я пробовал решение, предложенное в единственном ответе. Несмотря на то, что это действительно позволяет отделить кусок поставщика от общего объема, куски поставщика (с тем же определением), сделанные из двух отдельных сборок, вообще не могут быть обменены друг на друга. Это не позволяет использовать только один из этих блоков поставщика в двух сборках (хотя они практически одинаковы).
Ответы
Ответ 1
Я работал над чем-то подобным. Я наблюдал поведение, которое вы желаете, имея такую конфигурацию:
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. после добавления "таблицы фиксированных данных" в список поставщиков, которые исчезли, и единственный код исходного кода, который был там, был в vendor.bundle.js Я предполагаю, что это то, что вы искали? (в конце концов каждый поставщик, не указанный в списке поставщиков, попадал в каждый собственный module.bundle.js или в commons.bundle.js, если он был повторно использован в нескольких пакетах)
Отношения
Jonas
Ответ 2
Что касается вашего запроса, чтобы иметь возможность использовать кусок поставщика, созданный в одном пакете webpack с помощью пакетов из другой сборки, единственный способ, который я нашел для этого, - это сочетание expose-loader и externals
.
В моем случае я успешно использовал это, чтобы связать jQuery (и Bootstrap) с "common.js" в одной сборке, а затем использовать этот jQuery в модулях, принадлежащих другой сборке, следующим образом:
1. Expose jQuery из сборки A chunk
module: {
loaders: [
{
// export jQuery globals for other modules to use as externals
test: require.resolve('jquery'),
loader: 'expose?$!expose?jQuery'
}
]
}
2. Потребление jQuery в модулях build B
externals: {
'jquery': 'jQuery'
}
Конечно, недостатком этого является то, что вы соединяетесь между двумя наборами пакетов, используя управляемые вручную глобальные переменные, которые вы, вероятно, начали использовать webpack, чтобы избежать: -)
Однако в данный момент я не знаю другого способа, учитывая, что каждая сборка webpack создает собственное пространство имен "private" идентификаторов внутри для ссылок на модули, без гарантии стабильности или глобальной уникальности.