Webpack ProvidePlugin vs externos?

84

Estou explorando a ideia de usar o Webpack com Backbone.js .

Eu segui o guia de início rápido e tenho uma ideia geral de como o Webpack funciona, mas não estou certo sobre como carregar a biblioteca de dependências como jquery / backbone / underscore.

Eles devem ser carregados externamente <script>ou é algo que o Webpack pode manipular como o shim do RequireJS?

De acordo com o documento do webpack: módulos shimming , ProvidePlugine externalsparecem estar relacionados a isso (o bundle!carregador também está em algum lugar), mas não consigo descobrir quando usá -los .

obrigado

Henry
fonte

Respostas:

153

Ambos são possíveis: você pode incluir bibliotecas com um <script>(ou seja, usar uma biblioteca de um CDN) ou incluí-los no pacote gerado.

Se você carregá-lo via <script>tag, você pode usar a externalsopção para permitir a escrita require(...)em seus módulos.

Exemplo com biblioteca do 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");

Exemplo com biblioteca incluída no pacote:

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");

O ProvidePluginpode mapear módulos para variáveis ​​(livres). Então você pode definir: "Toda vez que eu usar a variável (livre) xyzdentro de um módulo que você (Webpack) deve definir xyza require("abc")".

Exemplo sem ProvidePlugin:

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

Exemplo com ProvidePlugin:

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

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

Resumo:

  • Biblioteca do CDN: Use <script>tag e externalsopção
  • Biblioteca do sistema de arquivos: inclui a biblioteca no pacote. (Talvez modifique as resolveopções para encontrar a biblioteca)
  • externals: Disponibilizar vars globais como módulo
  • ProvidePlugin: Disponibilizar módulos como variáveis ​​livres dentro dos módulos
Tobias K.
fonte
Deve adicionar newantes de webpack.ProvidePlugin webpack.github.io/docs/list-of-plugins.html
MK Yung
Por que não usar apenas o carregador de script? Isso é muito mais fácil, como @dtothefp explicou
timaschew
Se meu arquivo webpack.config estiver em uma pasta chamada javascript e dentro dela eu tenho uma pasta chamada vendor com meu arquivo jquery. deveria o caminho não ser. resolver: {alias: {jquery: "vendor / jquery-1.10.2.js"}}. Ainda não funciona para mim usando o alias
me-me
3
Basta passar um caminho absoluto para a opção de alias. Se você passar um caminho relativo, ele é relativo ao local de require / import no webpack 1. No webpack 2 é relativo ao arquivo webpack.config.js resp. a opção de contexto.
Tobias K.
@TobiasK. Um caminho absoluto não coopera com as exportações padrão. Estou recebendo um objeto em {__esModule: true, default: MY_DEFAULT_EXPORT}vez de MY_DEFAULT_EXPORTnos arquivos.
mgol
26

Algo interessante de se notar é que se você usar o ProvidePluginem combinação com a externalspropriedade, isso permitirá que você tenha jQuerypassado para o encerramento do módulo do webpack sem ter que explicitamente require. Isso pode ser útil para refatorar código legado com vários arquivos de referência $.

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

agora em index.js

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

terá uma saída compilada com algo como abaixo passado para o webpackBootstrapencerramento:

/******/ ([
/* 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;

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

Portanto, você pode ver que está fazendo $referência à janela global / jQuerydo CDN, mas está sendo passado para o encerramento. Não tenho certeza se esta é uma funcionalidade pretendida ou um hack de sorte, mas parece funcionar bem para o meu caso de uso.

dtothefp
fonte
você não precisava de nenhum dos plugins se não fosse acessá- require/importlo. $só funcionaria porque alcançaria o escopo global, não importa o quê. O ProviderPluginrequer a análise do AST, portanto, é um plugin caro e aumentará visivelmente o tempo de construção. Portanto, é basicamente um desperdício.
faceyspacey.com
@dtohefp esta resposta é uma dádiva de Deus. Você pode explicar por que ProvidePluginretornou um objeto como, a myModule.defaultmenos que eu tenha adicionado o módulo aos externos? Eu nunca soube que haveria qualquer relacionamento direto.
Slbox de
11

Eu sei que este é um post antigo, mas achei que seria útil mencionar que o carregador de script do webpack também pode ser útil neste caso. Dos documentos do webpack:

"script: executa um arquivo JavaScript uma vez no contexto global (como na tag de script), requer que não sejam analisados."

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

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

Achei isso particularmente útil ao migrar processos de construção mais antigos que concatam arquivos de fornecedores JS e arquivos de aplicativos. Uma palavra de advertência é que o carregador de script parece funcionar apenas com sobrecarga require()e não funciona, pelo que posso dizer, sendo especificado em um arquivo webpack.config. Embora muitos argumentem que a sobrecarga requireé uma prática ruim, pode ser bastante útil para conciliar o fornecedor e o script do aplicativo em um pacote e, ao mesmo tempo, expor JS Globals que não precisam ser reduzidos em pacotes de webpack adicionais. Por exemplo:

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

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

Isso tornaria $ .cookie, History e moment globalmente disponíveis dentro e fora deste pacote e agruparia essas bibliotecas de fornecedores com o script main.js e todos os seus requirearquivos d.

Além disso, é útil com esta técnica:

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

que está usando o Bower, examinará o mainarquivo em cada required bibliotecas package.json. No exemplo acima, History.js não tem um mainarquivo especificado, portanto, o caminho para o arquivo é necessário.

dtothefp
fonte