概念:
webpack是一个静态打包器,能够分析文件之间的依赖关系,递归地构建一个依赖关系图,最后将程序需要的每个模块都打包在一个bundle.js中。其实webpack的思想很简单,就是对代码进行模块化管理,分析代码之间的依赖关系,然后对其进行修改,把所有的资源都打包组织在一个大的bundle.js里。

功能:
概括webpack承担的主要责任有:
- 转译。把ES6,Typescript等语法语言通过loader转换成普通JS,让浏览器运行顺利。
- 打包。把多个文件(js, css,或者是图片)打包在一个bundle.js中,减少服务器压力。
- 优化。前端变得越来越复杂之后,性能也会存在问题,webpack开始可以肩负起优化和性能提升的责任。
Why Webpack?
- webpack 是以 commonJS 的形式来书写脚本的,但对 AMD/CMD 的支持也很全面,方便旧项目进行代码迁移。
- 能被模块化的不仅仅是 JS 了,还有css,less,react,json,vue等等。
- 扩展性强,具有强大的插件(Plugin)接口,使用起来比较灵活,特别是支持热插拔的功能很实用。
- 可以将代码切割成不同的块(chunk),每个块包含一个或多个模块,块可以按需被异步加载,降低了初始化时间。
核心:__webpack_require__
webpack的核心是一个__webpack_require__()
函数
例(阮一峰webpack demo11):
// main.js
var load = require('bundle-loader!./a.js');
load(function(file) {
document.open();
document.write('<h1>' + file + '</h1>');
document.close();
});
// a.js
module.exports = 'Hello World';
// webpack.config.js
module.exports = {
entry: './main.js',
output: {
filename: 'bundle.js'
}
};
// bundle.js
/******/ (function(modules) { // webpackBootstrap
/******/ // install a JSONP callback for chunk loading
/******/ .............
/******/
/******/ // The module cache
/******/ var installedModules = {};
/******/ function __webpack_require__(moduleId) {
/******/
/******/ // Check if module is in cache
/******/ if(installedModules[moduleId]) {
/******/ return installedModules[moduleId].exports;
/******/ }
/******/ // Create a new module (and put it into the cache)
/******/ var module = installedModules[moduleId] = {
/******/ i: moduleId,
/******/ l: false,
/******/ exports: {}
/******/ };
/******/
/******/ // Execute the module function
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/
/******/ // Flag the module as loaded
/******/ module.l = true;
/******/
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/
/******/ //以下省略__webpack_require__功能函数
/******/ ................
/******/
/******/ // Load entry module and return exports
/******/ return __webpack_require__(__webpack_require__.s = 0);
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ (function(module, exports, __webpack_require__) {
var load = __webpack_require__(1);
load(function(file) {
document.open();
document.write('<h1>' + file + '</h1>');
document.close();
});
/***/ }),
/* 1 */
/***/ (function(module, exports, __webpack_require__) {
var cbs = [],
data;
module.exports = function(cb) {
if(cbs) cbs.push(cb);
else cb(data);
}
__webpack_require__.e/* require.ensure */(0).then((function(require) {
data = __webpack_require__(2);
var callbacks = cbs;
cbs = null;
for(var i = 0, l = callbacks.length; i < l; i++) {
callbacks[i](data);
}
}).bind(null, __webpack_require__)).catch(__webpack_require__.oe);
/***/ })
/******/ ]);
// 0.bundle.js
webpackJsonp([0],{
/***/ 2:
/***/ (function(module, exports) {
module.exports = 'Hello World';
/***/ })
});
其实这个函数主要的作用就是自己定义了一个CommonJS的对象,并且放入缓存;这个立即执行函数传入的是模块函数的数组,moduleId
为入口函数的编号(代码中编号为0),module中的代表的就是当前模块是否被调用,用于判定后续模块调用的钩子函数。首先需要加载入口文件
main.js
,在main.js
中需要加载a.js
,于是在bundle文件中就运行__webpack_require__(1)
,在a.js
中需要加载json字符串,于是在bundle文件中就运行__webpack_require__(2)
,以此类推。所有的依赖的模块就是这样动态地、递归地在runtime完成加载,并被放入InstalledModules
缓存。
loader
webpack本身只能对javascript文件进行打包,而对于非js文件,就要使用loader来“翻译”。loader用来对资源(如css,less,json,框架等)进行预处理,可以将不是js的文件打包转换成js,也可以将ES6+语法转换成普通js语法,便于浏览器执行。
在webpack中推荐在webpack.config.js
文件中指定loader:
module: {
rules: [
{
test: /\.css$/, /* 匹配文件类型*/
use: [
{ loader: 'style-loader' },
{
loader: 'css-loader',
options: {
modules: true
}
}
]
}
]
}
有哪些loader:
- 转换编译:
babel-loader
:加载 ES2015+ 代码,然后使用 Babel 转译为 ES5
script-loader
:在全局上下文中执行一次 JavaScript 文件(如在 script 标签),不需要解析
ts-loader
或awesome-typescript-loader
:像 JavaScript 一样加载 TypeScript 2.0+
coffee-loader
:像 JavaScript 一样加载 CoffeeScript - 样式编译:
style-loader
:将模块的导出作为样式添加到 DOM 中
css-loader
: 解析 CSS 文件后,使用 import 加载,并且返回 CSS 代码
less-loader
: 加载和转译 LESS 文件
sass-loader
:加载和转译 SASS/SCSS 文件 - 模板编译:
markdown-loader
: 将 Markdown 转译为 HTML
react-markdown-loader
:使用 markdown-parse parser(解析器) 将 Markdown 编译为 React 组件 - 清理测试:
eslint-loader
: PreLoader,使用 ESLint 清理代码 - 框架编译:
vue-loader
: 加载和转译 Vue 组件
angular2-template-loader
:加载和转译 Angular 组件
loader特性:
-
链式传递。
从右到左编译,第一个loader的编译输出作为第二个loader的输入,最后返回webpack支持的javascript。
注意:在modules.rules
中,use所定义的数组内loader顺序不能错,比如需要编译less
文件,use中应该写的是[ 'style-loader','css-loader','less-loader']
。因为loader是链式传递的,less-loader的输出是.css
,才可以作为css-loader的输入,如果顺序不对就会报错。 -
支持同步和异步。
第一个 loader 的传入参数只有一个:资源文件(resource file)的内容。compiler 需要得到最后一个 loader 产生的处理结果。这个处理结果应该是String
或者Buffer
(被转换为一个 string),代表了模块的 JavaScript 源码。另外还可以传递一个可选的 SourceMap 结果(格式为 JSON 对象)。
如果是单个处理结果,可以在同步模式中直接返回。如果有多个处理结果,则必须调用this.callback()
。在异步模式中,必须调用this.async()
,来指示 loader runner 等待异步结果,它会返回this.callback()
回调函数,随后 loader 必须返回undefined
并且调用该回调函数。 -
loader 接收查询参数。用于对 loader 传递配置。
参考链接:
https://segmentfault.com/a/1190000013761990
https://www.jianshu.com/p/236466fc0033?tdsourcetag=s_pcqq_aiomsg
网友评论