Webpack ProvidePlugin a zewnętrzne?

84

Badam pomysł wykorzystania Webpack z Backbone.js .

Postępowałem zgodnie z przewodnikiem szybkiego startu i mam ogólne pojęcie o tym, jak działa Webpack, ale nie jestem pewien, jak załadować bibliotekę zależności, taką jak jquery / backbone / underscore.

Czy powinny być ładowane zewnętrznie, <script>czy jest to coś, co Webpack może obsługiwać, jak podkładka RequireJS?

Według doc WebPACK: podkładek modułów , ProvidePlugini externalswydają się być podobne do tego (tak jest bundle!ładowarka gdzieś), ale nie mogę dowiedzieć się, kiedy używać które.

Dzięki

Henz
źródło

Odpowiedzi:

153

Jest to możliwe: możesz dołączyć biblioteki za pomocą <script>(tj. Użyć biblioteki z CDN) lub dołączyć je do wygenerowanego pakietu.

Jeśli załadujesz go za pomocą <script>tagu, możesz użyć externalsopcji, aby zezwolić na zapis require(...)w swoich modułach.

Przykład z biblioteką z CDN:

<script src="https://code.jquery.com/jquery-git2.min.js"></script>

// the artifial module "jquery" exports the global var "jQuery"
externals: { jquery: "jQuery" }

// inside any module
var $ = require("jquery");

Przykład z biblioteką zawartą w pakiecie:

copy `jquery-git2.min.js` to your local filesystem

// make "jquery" resolve to your local copy of the library
// i. e. through the resolve.alias option
resolve: { alias: { jquery: "/path/to/jquery-git2.min.js" } }

// inside any module
var $ = require("jquery");

ProvidePluginMoże odwzorowywać moduły do (wolnych) zmiennych. Tak można określić: „Za każdym razem używam (bezpłatny) zmienną xyzwewnątrz modułu, który (WebPack) należy ustawić xyzna require("abc")”.

Przykład bez ProvidePlugin:

// You need to require underscore before you can use it
var _ = require("underscore");
_.size(...);

Przykład z ProvidePlugin:

plugins: [
  new webpack.ProvidePlugin({
    "_": "underscore"
  }) 
]

// If you use "_", underscore is automatically required
_.size(...)

Podsumowanie:

  • Biblioteka z CDN: użyj <script>tagu i externalsopcji
  • Biblioteka z systemu plików: dołącz bibliotekę do pakietu. (Może zmodyfikuj resolveopcje, aby znaleźć bibliotekę)
  • externals: Udostępnij zmienne globalne jako moduł
  • ProvidePlugin: Udostępnij moduły jako wolne zmienne wewnątrz modułów
Tobias K.
źródło
Należy dodać newprzed webpack.ProvidePlugin webpack.github.io/docs/list-of-plugins.html
MK Yung
Dlaczego po prostu nie użyć programu ładującego skrypt? Jest to znacznie łatwiejsze, jak wyjaśnił
@dtothefp
Jeśli mój plik webpack.config znajduje się w folderze o nazwie javascript, a wewnątrz niego znajduje się folder o nazwie vendor z moim plikiem jquery. czy ścieżka nie powinna być. rozwiąż: {alias: {jquery: "vendor / jquery-1.10.2.js"}}. Nadal nie działa dla mnie przy użyciu aliasu
me-me
3
Po prostu podaj bezwzględną ścieżkę do opcji aliasu. Jeśli podasz ścieżkę względną, jest ona względna w stosunku do lokalizacji wymagania / importu w pakiecie internetowym 1. W pakiecie internetowym 2 jest to względne w stosunku do pliku webpack.config.js. opcja kontekstowa.
Tobias K.
@TobiasK. Ścieżka bezwzględna nie współpracuje z domyślnymi eksportami. Otrzymuję obiekt {__esModule: true, default: MY_DEFAULT_EXPORT}zamiast MY_DEFAULT_EXPORTw plikach.
mgol
25

Warto zauważyć, że jeśli użyjesz atrybutu ProvidePluginw połączeniu z externalswłaściwością, pozwoli ci to jQueryprzejść do zamknięcia modułu webpacka bez konieczności jawnego requiretego. Może to być przydatne do refaktoryzacji starszego kodu z odwołaniami do wielu różnych plików $.

//webpack.config.js
module.exports = {
  entry: './index.js',
  output: { 
    filename: '[name].js' 
  },
  externals: {
    jquery: 'jQuery'
  },
  plugins: [
    new webpack.ProvidePlugin({
      $: 'jquery',
    })
  ]
};

teraz w index.js

console.log(typeof $ === 'function');

będzie miał skompilowane wyjście z czymś takim jak poniżej przekazanym do webpackBootstrapzamknięcia:

/******/ ([
/* 0 */
/***/ function(module, exports, __webpack_require__) {

    /* WEBPACK VAR INJECTION */(function($) {
        console.log(typeof $ === 'function');

    /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(1)))

/***/ },
/* 1 */
/***/ function(module, exports, __webpack_require__) {

    module.exports = jQuery;

/***/ }
/******/ ])

Dlatego widzisz, że $odwołuje się do global / window jQueryz CDN, ale jest przekazywany do zamknięcia. Nie jestem pewien, czy jest to zamierzona funkcjonalność, czy szczęśliwy hack, ale wydaje się, że działa dobrze w moim przypadku użycia.

dtothefp
źródło
nie potrzebowałeś żadnej wtyczki, jeśli nie zamierzałeś tego robić require/import. $zadziała, ponieważ bez względu na wszystko osiągnie zasięg globalny. ProviderPluginWymaga analizowania AST więc jest to drogie wtyczki i doda do czasu kompilacji zauważalnie. Więc to w zasadzie marnotrawstwo.
faceyspacey.com
@dtohefp ta odpowiedź jest wybawieniem. Czy możesz ewentualnie wyjaśnić, dlaczego ProvidePluginzwrócił obiekt taki jak, myModule.defaultchyba że dodałem moduł do zewnętrznych? Nigdy nie wiedziałem, że będzie jakikolwiek bezpośredni związek.
Slbox
11

Wiem, że to stary post, ale pomyślałem, że warto wspomnieć, że moduł ładujący skrypt pakietu webpack może być przydatny również w tym przypadku. Z dokumentów pakietu internetowego:

„script: jednorazowo wykonuje plik JavaScript w kontekście globalnym (np. w tagu skryptu), wymagania nie są analizowane”.

http://webpack.github.io/docs/list-of-loaders.html

https://github.com/webpack/script-loader

Zauważyłem, że jest to szczególnie przydatne podczas migracji starszych procesów kompilacji, które łączą ze sobą pliki dostawców JS i pliki aplikacji. Ostrzeżenie jest takie, że moduł ładujący skrypt wydaje się działać tylko przez przeciążenie require()i nie działa tak daleko, jak mogę to stwierdzić, ponieważ jest określony w pliku webpack.config. Chociaż wielu twierdzi, że przeciążanie requirejest złą praktyką, może być całkiem przydatne do łączenia skryptu dostawcy i aplikacji w jednym pakiecie, a jednocześnie ujawniania JS Globals, których nie trzeba umieszczać w dodatkowych pakietach webpack. Na przykład:

require('script!jquery-cookie/jquery.cookie');
require('script!history.js/scripts/bundled-uncompressed/html4+html5/jquery.history');
require('script!momentjs');

require('./scripts/main.js');

Spowodowałoby to, że $ .cookie, historia i moment byłyby globalnie dostępne w tym pakiecie i poza nim oraz wiązałyby te biblioteki dostawców ze skryptem main.js i wszystkimi jego requireplikami d.

Przydatne w tej technice jest również:

resolve: {
  extensions: ["", ".js"],
  modulesDirectories: ['node_modules', 'bower_components']
},
plugins: [
  new webpack.ResolverPlugin(
    new webpack.ResolverPlugin.DirectoryDescriptionFilePlugin("bower.json", ["main"])
   )
]

który używa Bower, przejrzy mainplik w każdej z requirebibliotek pakiet.json. W powyższym przykładzie History.js nie ma mainokreślonego pliku, więc ścieżka do pliku jest niezbędna.

dtothefp
źródło