Pytanie Webpack z dwoma typowymi porcjami: jeden wyeksportowany, jeden lokalny


Chciałbym używać Webpacka w wielostronicowej aplikacji w taki sposób, że niektóre wstępnie określone zależności są łączone w porcję "dostawcy", a pozostałe zależności są łączone w porcję "wspólnych".

Na przykład, zakładając dwa punkty wejścia (w rzeczywistości reprezentujące inną stronę), pageA.js i pageB.js zawierają zarówno ten kod (w EC6, przetwarzany przez Babel), jak i jego własny kod:

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

Chciałbym, aby jQuery i Bootstrap były dołączone do kawałka "dostawcy", a reszta (cokolwiek to jest), aby była dołączona do kawałka "wspólnego".

Cele są następujące:

  • Chciałbym mieć inną oddzielną kompilację, która byłaby w stanie polegać na tym samym fragmencie dostawcy, bez konieczności ponownego dołączania bibliotek dostawców (wyraźnie deklarowałbym ten zestaw bibliotek dostawców, aby był dostępny dla każdego dostawcy. podbudowa, która tego potrzebuje).
  • Nie chciałbym też ponownie przetwarzać kawałka dostawcy za każdym razem, gdy wprowadzam zmianę w skrypcie strony.

Oto konfiguracja, którą wypróbowałem:

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
        })
    ]
};

W powyższej konfiguracji otrzymuję jQuery i Bootstrap vendor.chunk.js, w razie potrzeby, ale commons.chunk.js plik jest prawie pusty, cała reszta tego, co jest powszechnie używane pageA.js i pageB.js jest następnie wprowadzane pageA.chunk.js i pageB.chunk.js (skutecznie powielając ten kod).

Jeśli zamieniam kolejność dwóch ostatnich wtyczek, commons.chunk.js zawiera teraz prawie wszystko (chyba, że ​​jest to coś konkretnego pageA.js i pageB.js), i vendor.chunk.js jest prawie pusty:

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

Czy istnieje sposób na zestawienie wcześniej zdefiniowanej listy bibliotek (np. [ "jquery", "jquery-ui", "bootstrap" ] w jedną konkretną porcję (w taki sposób, aby mógł być używany przez całkowicie niezależne skrypty), a także mieć inną wspólną część z tego, co jeszcze jest powszechnie używane między punktami wejścia?

Celem tego wszystkiego byłaby możliwość zbudowania całkowicie oddzielnego fragmentu kodu dla innej strony później i powiedzenie mu, że nie musi ponownie pakować tych wstępnie zdefiniowanych bibliotek.

Oto diagram przedstawiający to, co próbuję osiągnąć:

Dependencies Diagram

Następnie użyłbym generowanych skryptów na stronie A:

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

I na stronie C (zbudowanej całkowicie niezależnie od stron A i B):

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

(Używam Webpack 1.12.14.)


Próbowałem rozwiązania sugerowanego w jedyna odpowiedź do tej pory. Chociaż w ten sposób możliwe jest oddzielenie fragmentu dostawcy od fragmentu commons, fragmenty dostawcy (o tej samej definicji) utworzone z dwóch oddzielnych kompilacji zasadniczo nie mogą być zamienione między sobą. Nie pozwala to na użycie tylko jednej z tych części dostawcy w dwóch wersjach (mimo że są praktycznie takie same).


16
2018-02-23 18:16


pochodzenie




Odpowiedzi:


Pracowałem nad czymś podobnym. Obserwowałem zachowanie, którego pragniesz, mając tę ​​konfigurację:

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
        })
    ];

więc ten kod powyżej pozostawił w b.bundle.js wciąż jakiś import React i innych bibliotek React. po dodaniu "listy stałych danych" do listy dostawców, która zniknęła, a jedyny możliwy kod źródłowy był w vendor.bundle.js. Zakładam, że tego właśnie szukałeś? (w końcu każdy sprzedawca niewymieniony na liście dostawców znalazł się w każdym module module.bundle.js lub w commons.bundle.js, jeśli był ponownie użyty w wielu pakietach)

pozdrowienia Jonas


10
2018-03-03 14:59



Nota boczna: używanie nowej CommonsChunkPlugin ({nazwa: "sprzedawca", nazwa pliku: "vendor.bundle.js", fragmenty: ["sprzedawca"], minChunks: Infinity}) zamiast nowej CommonsChunkPlugin ("sprzedawca", "vendor.bundle" .js ") nie działa. - jonas.hartwig
Dziękuję Ci. Wydaje się, że działa to w zakresie oddzielania dostawcy i bibliotek wspólnych, ale wciąż brakuje aspektu (lub przynajmniej nie mogę go uruchomić): możliwość ponownego wykorzystania tego samego vendor.bundle.js z oddzielnego podprojektu ("Strona C" w moim przykładzie). Próbowałem zbudować dwa podprojekty w ten sposób (zmieniając nazwę na "sprzedawca" i "wspólny" wynik) i sprawić, aby jedna strona korzystała z pliku "dostawcy" drugiej, ale to nie działa. Nie mogę wydawać się być w stanie uzyskać pakiet dostawcy, który jest użyteczny przez cokolwiek, niezależnie od projektu Webpack. - Bruno
tak, nie rozumiem, jak to działoby atm - jonas.hartwig
Mimo wszystko dziekuję. - Bruno
@ jonas.hartwig Wspomniałeś, że dodałeś "tabelę danych stałych" do swojej listy dostawców, aby naprawić problem, w którym część kodu reakcji pojawia się w pliku common.js. Czy możesz rozwinąć nieco więcej o tym, co masz na myśli, dodając "tabelę danych stałych"? Dzięki! - Carven


Jeśli chodzi o twoją prośbę o możliwość użycia fragmentu dostawcy utworzonego w jednej kompilacji pakietu WWW za pomocą pakietów z innej kompilacji, jedyny sposób, jaki znalazłem, to poprzez połączenie expose-loader i externals.

W moim przypadku z powodzeniem wykorzystałem to do dołączenia jQuery (i Bootstrap) do "common.js" w jednej kompilacji, a następnie użycie tego jQuery w modułach należących do innej kompilacji, jak następuje:

1. Ujawnij jQuery z fragmentu kompilacji A

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

2. Zużyj jQuery w modułach B budowy

externals: {
  'jquery': 'jQuery'
}

Oczywiście, wadą tego jest to, że przechodzisz pomiędzy dwoma zestawami pakietów, używając ręcznie zarządzanych globalnych zmiennych, które prawdopodobnie zaczęły używać webpacka, aby uniknąć :-)

Jednak nie wiem na ten temat w żaden inny sposób, biorąc pod uwagę, że każda kompilacja pakietu WWW tworzy własną przestrzeń nazw "prywatnych" identyfikatorów wewnętrznie w odniesieniu do modułów referencyjnych, bez gwarancji stabilności lub globalnej wyjątkowości.


2
2017-07-12 18:28