Webpack 提供外部插件 VS 外部插件?

我正在探索将 网络包Backbone js结合使用的想法。

我已经遵循了快速入门指南,并且对 Webpack 的工作原理有了一个大致的了解,但是我不清楚如何加载依赖项库,比如 jquery/main/underscore。

它们是应该外部加载 <script>,还是 Webpack 可以像 RequreJS 的垫片那样处理它们?

根据 Webpack 文档: 垫片模块ProvidePluginexternals似乎与此有关(因此是 bundle!加载程序的地方) ,但我不能指出什么时候使用哪一个。

谢谢

52546 次浏览

It's both possible: You can include libraries with a <script> (i. e. to use a library from a CDN) or include them into the generated bundle.

If you load it via <script> tag, you can use the externals option to allow to write require(...) in your modules.

Example with library from 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");

Example with library included in bundle:

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

The ProvidePlugin can map modules to (free) variables. So you could define: "Every time I use the (free) variable xyz inside a module you (webpack) should set xyz to require("abc")."

Example without ProvidePlugin:

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

Example with ProvidePlugin:

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


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

Summary:

  • Library from CDN: Use <script> tag and externals option
  • Library from filesystem: Include the library in the bundle. (Maybe modify resolve options to find the library)
  • externals: Make global vars available as module
  • ProvidePlugin: Make modules available as free variables inside modules

I know this is an old post but thought it would be useful to mention that the webpack script loader may be useful in this case as well. From the webpack docs:

"script: Executes a JavaScript file once in global context (like in script tag), requires are not parsed."

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

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

I have found this particularly useful when migrating older build processes that concat JS vendor files and app files together. A word of warning is that the script loader seems only to work through overloading require() and doesn't work as far as I can tell by being specified within a webpack.config file. Although, many argue that overloading require is bad practice, it can be quite useful for concating vendor and app script in one bundle, and at the same time exposing JS Globals that don't have to be shimmed into addition webpack bundles. For example:

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


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

This would make $.cookie, History, and moment globally available inside and outside of this bundle, and bundle these vendor libs with the main.js script and all it's required files.

Also, useful with this technique is:

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

which is using Bower, will look at the main file in each required libraries package.json. In the above example, History.js doesn't have a main file specified, so the path to the file is necessary.

Something cool to note is that if you use the ProvidePlugin in combination with the externals property it will allow you to have jQuery passed into your webpack module closure without having to explicitly require it. This can be useful for refactoring legacy code with a lot of different files referencing $.

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

now in index.js

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

will have a compiled output with something like below passed into the webpackBootstrap closure:

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


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

Therefore, you can see that $ is referencing the global/window jQuery from the CDN, but is being passed into the closure. I'm not sure if this is intended functionality or a lucky hack but it seems to work well for my use case.