Satıcı komut dosyalarını ayrı ayrı nasıl paketleyebilir ve Webpack ile gerektiği gibi nasıl gerektirir?


173

Mümkün olması gerektiğine inandığım bir şey yapmaya çalışıyorum, ancak bunu sadece web paketi belgelerinden nasıl yapacağımı gerçekten anlayamıyorum.

Birbirine bağlı olan veya olmayan birkaç modül içeren bir JavaScript kitaplığı yazıyorum. Bunun da ötesinde, jQuery tüm modüller tarafından kullanılır ve bazıları jQuery eklentilerine ihtiyaç duyabilir. Bu kütüphane daha sonra modüllerin bir kısmını veya tamamını gerektirebilecek birkaç farklı web sitesinde kullanılacaktır.

Modüllerim arasındaki bağımlılıkları tanımlamak çok kolaydı, ancak üçüncü taraf bağımlılıklarını tanımlamak beklediğimden daha zor görünüyor.

Neyi başarmak istiyorum : Her uygulama için gerekli üçüncü taraf bağımlılıklarına ve diğer kütüphanemden gerekli modüllere sahip iki paket dosyasına sahip olmak istiyorum.

Örnek : Kütüphanemde aşağıdaki modüllerin bulunduğunu düşünelim:

  • a (gerektirir: jquery, jquery.plugin1)
  • b (gerektirir: jquery, a)
  • c (gerektirir: jquery, jquery.ui, a, b)
  • d (gerektirir: jquery, jquery.plugin2, a)

Ve a, b ve c modülleri gerektiren bir uygulamam var (benzersiz bir giriş dosyası olarak bakın). Bu vaka için Webpack aşağıdaki dosyaları oluşturmalıdır:

  • satıcı paketi : jquery, jquery.plugin1 ve jquery.ui ile;
  • web sitesi paketi : a, b ve c modülleri ile;

Sonunda, ben her bir dosyada (örneğin sadece ana dosyada gerektirebilir) gerek yok böylece jQuery küresel olarak tercih ederim. Ve jQuery eklentileri, gerektiğinde $ global'i genişletir (bunlara ihtiyaç duymayan diğer modüller tarafından kullanılabilirse sorun olmaz).

Bunun mümkün olduğunu varsayarsak, bu durumda bir web paketi yapılandırma dosyasına bir örnek ne olabilir? Yapılandırma dosyamda birkaç yükleyici, harici ve eklenti kombinasyonu denedim, ancak ne yaptıklarını ve hangilerini kullanmam gerektiğini gerçekten anlamıyorum. Teşekkür ederim!


2
çözümün nedir iyi bir yaklaşım bulmayı başardın mı? Eğer öyleyse lütfen gönderin! teşekkürler
GeekOnGadgets

Yanıtlar:


140

webpack.config.js (Sürüm 1,2,3) dosyamda var

function isExternal(module) {
  var context = module.context;

  if (typeof context !== 'string') {
    return false;
  }

  return context.indexOf('node_modules') !== -1;
}

eklentiler dizimde

plugins: [
  new CommonsChunkPlugin({
    name: 'vendors',
    minChunks: function(module) {
      return isExternal(module);
    }
  }),
  // Other plugins
]

Şimdi gerektiği gibi bir dosyaya sadece 3. parti libs ekleyen bir dosya var.

Satıcılarınızı ve giriş noktası dosyalarınızı ayırdığınız yerde daha ayrıntılı bilgi almak istiyorsanız:

plugins: [
  new CommonsChunkPlugin({
    name: 'common',
    minChunks: function(module, count) {
      return !isExternal(module) && count >= 2; // adjustable
    }
  }),
  new CommonsChunkPlugin({
    name: 'vendors',
    chunks: ['common'],
    // or if you have an key value object for your entries
    // chunks: Object.keys(entry).concat('common')
    minChunks: function(module) {
      return isExternal(module);
    }
  })
]

Eklentilerin sırasının çok önemli olduğunu unutmayın.

Ayrıca, bu sürüm 4'te değişecek. Bu resmi olduğunda, bu yanıtı güncelliyorum.

Güncelleme: windows kullanıcıları için indexOf arama değişikliği


1
Sorumu gönderdiğimde bunun mümkün olup olmadığını bilmiyorum, ama aradığım şey bu. Bu çözümle artık satıcı giriş yığınımı belirtmem gerekmiyor. Çok teşekkürler!
bensampaio

1
isExternaliçinde minChunksbenim gün yaptı. Bu nasıl belgelenmiyor? Dezavantajları var mı?
Wesley Schleumer de Góes

Thx, ancak windows yolları için userRequest.indexOf ('/ node_modules /') öğesini userRequest.indexOf ('node_modules') olarak değiştirin
Kinjeiro 19:16

@ WesleySchleumerdeGóes belgelenmiş ama örnek olmadan options.minChunks (number|Infinity|function(module, count) -> boolean):henüz bir dezavantajı görmüyorum.
Rafael De Leon

2
Yükleyicinin yolu da içinde olacağından module.userRequest(ve yükleyici muhtemelen içeride olduğundan node_modules) , yükleyiciler kullanılırken bu çalışmaz . isExternal()return typeof module.userRequest === 'string' && !!module.userRequest.split('!').pop().match(/(node_modules|bower_components|libraries)/);
Kodum

54

Sorununuzu tam olarak anladığımdan emin değilim ama son zamanlarda benzer bir sorun yaşadığımdan size yardımcı olmaya çalışacağım.

Satıcı paketi.

Bunun için CommonsChunkPlugin kullanmalısınız . yapılandırmada öbek adını (örneğin vendor) ve oluşturulacak dosya adını ( vendor.js) belirtirsiniz .

new webpack.optimize.CommonsChunkPlugin("vendor", "vendor.js", Infinity),

Şimdi önemli olan, şimdi vendorkütüphane ne anlama geldiğini belirtmeniz ve bunu bir giriş bölümünde yapmanız gerekir. Yeni ilan edilen parçanın adıyla aynı ada sahip giriş listesine bir öğe daha (yani, bu durumda 'satıcı'). Bu girdinin değeri, vendorpakete taşımak istediğiniz tüm modüllerin listesi olmalıdır . sizin durumunuzda şöyle görünmelidir:

entry: {
    app: 'entry.js',
    vendor: ['jquery', 'jquery.plugin1']
}

Global olarak JQuery

Aynı sorunu vardı ve ProvidePlugin ile çözdü . burada global nesneyi tanımlamıyorsunuz, modüller için bir tür kapanış yapıyorsunuz. yani şu şekilde yapılandırabilirsiniz:

new webpack.ProvidePlugin({
    $: "jquery"
})

Ve şimdi $kodunuzdaki herhangi bir yerde kullanabilirsiniz - webpack bunu otomatik olarak

require('jquery')

Umarım yardımcı olmuştur. ayrıca burada bulunan webpack yapılandırma dosyasına da bakabilirsiniz

Ben webpack seviyorum, ama belgelerin dünyanın en güzel olmadığını kabul ediyorum ... ama hey .. insanlar başlangıçta Açısal belgeler hakkında aynı şeyi söylüyorlardı :)


Düzenle:

Giriş noktasına özgü satıcı parçalarına sahip olmak için CommonsChunkPlugins'i birden çok kez kullanmanız yeterlidir:

new webpack.optimize.CommonsChunkPlugin("vendor-page1", "vendor-page1.js", Infinity),
new webpack.optimize.CommonsChunkPlugin("vendor-page2", "vendor-page2.js", Infinity),

ve sonra farklı dosyalar için farklı extenral kütüphaneler beyan edin:

entry: {
    page1: ['entry.js'],
    page2: ['entry2.js'],
    "vendor-page1": [
        'lodash'
    ],
    "vendor-page2": [
        'jquery'
    ]
},

Bazı kütüphaneler giriş noktaları arasında üst üste biniyorsa (ve çoğu için), sadece farklı yapılandırma ile aynı eklentiyi kullanarak onları ortak dosyaya çıkarabilirsiniz. Bu örneğe bakın .


Cevabınız için çok teşekkür ederim. Bu şimdiye kadar gördüğüm en iyi yaklaşımdı ama maalesef hala sorunumu çözmüyor ... Örneğinizi test ettim ve vendor.js dosyası hala 'jquery' ve 'jquery.plugin1' kodlarının tümünü içerecek olsa bile modüllerimden herhangi biri tarafından istenmiyor. Bu, sonunda tarayıcıya her zaman yüklenecekleri anlamına gelir. Çok sayıda jquery eklentisi varsa, bunların yarısı kullanılmış olsa bile bu çok büyük bir dosyaya neden olacaktır. 'Jquery.plugin1'i satıcı paketine yalnızca gerektiğinde dahil etmenin bir yolu yok mu?
bensampaio

teşekkürler, bu yüzden ben de bir şeyler öğrendim :) Ben birden çok satıcı-parçaları oluşturma ile cevabımı güncelledim. belki şimdi sana daha uygun olur.
Michał Margiel

4
Bu çözümün sorunu, her sayfa için bağımlılıkların ne olduğunu bildiğimi varsaymasıdır. Ama tahmin edemem ... jQuery sadece bir satıcı paketinde sadece sayfada kullanılan modüllerden biri tarafından gerekli olması durumunda dahil edilmelidir. Yapılandırma dosyasında, sayfada kullanılan herhangi bir modül tarafından gerekli olmasa bile her zaman satıcı paketinde olacağını belirterek, değil mi? Temel olarak, satıcı paketlerinin içeriğini tahmin edemiyorum, aksi takdirde yüzlerce çalıştığım sadece 2 sayfam olmadığı için bir işim olacak ... Sorun mu var? Herhangi bir fikir? :)
bensampaio

Ne dediğini anlıyorum ama bunu bir problem olarak görmüyorum. Bir sayfada yeni kitaplık kullanıyorsanız, kitaplığı o sayfa için satıcı kitaplığı listelerine eklemeniz yeterlidir. Sadece birkaç karakter. Zaten çözümünüzde, yükleyiciyi belirterek bunu yapmanız gerekir.Yeni oluşturulan modülün hangi sayfaların kullanılacağını bilmiyorsanız - CommonChuncks eklentisinin modüllerinizden ortak kütüphaneleri otomatik olarak çıkarmasına izin verin.
Michał Margiel

Satıcı dosyaları için bağlamı nasıl ayrı ayrı ayarlayabilirim?
harshes53

44

Komut dosyalarınızı satıcılardan ayrı olarak otomatik olarak paketlemek istiyorsanız:

var webpack = require('webpack'),
    pkg     = require('./package.json'),  //loads npm config file
    html    = require('html-webpack-plugin');

module.exports = {
  context : __dirname + '/app',
  entry   : {
    app     : __dirname + '/app/index.js',
    vendor  : Object.keys(pkg.dependencies) //get npm vendors deps from config
  },
  output  : {
    path      : __dirname + '/dist',
    filename  : 'app.min-[hash:6].js'
  },
  plugins: [
    //Finally add this line to bundle the vendor code separately
    new webpack.optimize.CommonsChunkPlugin('vendor', 'vendor.min-[hash:6].js'),
    new html({template : __dirname + '/app/index.html'})
  ]
};

Bu özellik hakkında daha fazla bilgiyi resmi belgelerden okuyabilirsiniz .


4
Lütfen vendor : Object.keys(pkg.dependencies) her zaman çalışmaz ve paketin nasıl oluşturulduğuna bağlıdır.
markyph

1
Her zaman nasıl package.jsonayarlandığına bağlısın. Bu geçici çözüm çoğu durumda çalışır, ancak farklı bir yol izlemeniz gereken istisnalar vardır. Topluluğa yardımcı olmak için soruya kendi cevabınızı göndermek ilginç olabilir.
Freezystem

17
Bunu severim. Beni biraz çiş yaptı.
cgatian

3
Hatta kodunuzda hiç kullanamayacağınız paketleri bile içereceğini unutmayın ... çünkü Object.keys(pkg.dependencies)her şeyi paketleyecektir !!!! orada listelenen bir sürü yükleyici var diyelim ... evet dahil olacak !!! öyleyse dikkat edin ... dikkatlice ayrı ayrı devDependency nedir ve bağımlılık nedir
Rafael Milewski

1
@RafaelMilewski neden yükleyiciniz olsun ki dependencies?
Pantolonlar

13

Ayrıca durumunuzu tam olarak anladığımdan emin değilim, ancak burada her bir paketiniz için ayrı satıcı parçaları oluşturmak için yapılandırma snippet'i var:

entry: {
  bundle1: './build/bundles/bundle1.js',
  bundle2: './build/bundles/bundle2.js',
  'vendor-bundle1': [
    'react',
    'react-router'
  ],
  'vendor-bundle2': [
    'react',
    'react-router',
    'flummox',
    'immutable'
  ]
},

plugins: [
  new webpack.optimize.CommonsChunkPlugin({
    name: 'vendor-bundle1',
    chunks: ['bundle1'],
    filename: 'vendor-bundle1.js',
    minChunks: Infinity
  }),
  new webpack.optimize.CommonsChunkPlugin({
    name: 'vendor-bundle2',
    chunks: ['bundle2'],
    filename: 'vendor-bundle2-whatever.js',
    minChunks: Infinity
  }),
]

Ve CommonsChunkPlugindokümanlara bağlantı : http://webpack.github.io/docs/list-of-plugins.html#commonschunkplugin


Bu çözümle ilgili sorunun Michal tarafından sağlanan sorunla aynı olduğuna inanıyorum. Bundle1 ve bundle2 için satıcı bağımlılıklarını bildiğimi varsayıyorsunuz, ancak yapmıyorum ... Yapılandırma dosyasında bunların tümünü belirtmek istediğiniz 200 paketiniz olduğunu düşünüyor musunuz? reactÖrneğinizi kullanmak, yalnızca paket1 ve paket2 tarafından açıkça isteniyorsa, satıcı paketinde bulunmalıdır. Bunu yapılandırma dosyasında belirtmem gerekmiyor ... Bu anlamlı mı? Herhangi bir fikir?
bensampaio

@Anakin soru, neden 200 satıcı aracını ayrı bir dosyada paketlemek istediğinizdir. Ortak araçları yalnızca ayrı bir dosyada toplar ve geri kalanını proje paketleriyle birlikte tutarım.
maxisam

@Anakin Aynı konuyla uğraşıyorum, yanılıyorsam beni düzeltin? stackoverflow.com/questions/35944067/…
pjdicke
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.