webpack

概念:

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


官方原理图

功能:

概括webpack承担的主要责任有:

  1. 转译。把ES6,Typescript等语法语言通过loader转换成普通JS,让浏览器运行顺利。
  2. 打包。把多个文件(js, css,或者是图片)打包在一个bundle.js中,减少服务器压力。
  3. 优化。前端变得越来越复杂之后,性能也会存在问题,webpack开始可以肩负起优化和性能提升的责任。

Why Webpack?

  1. webpack 是以 commonJS 的形式来书写脚本的,但对 AMD/CMD 的支持也很全面,方便旧项目进行代码迁移。
  2. 能被模块化的不仅仅是 JS 了,还有css,less,react,json,vue等等。
  3. 扩展性强,具有强大的插件(Plugin)接口,使用起来比较灵活,特别是支持热插拔的功能很实用。
  4. 可以将代码切割成不同的块(chunk),每个块包含一个或多个模块,块可以按需被异步加载,降低了初始化时间。

核心:__webpack_require__

webpack的核心是一个__webpack_require__()函数
例(阮一峰webpack demo11):

// main.js
var load = require('bundle-loader!./a.js');
load(function(file) {
  document.open();
  document.write('

' + file + '

'); 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('

' + file + '

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

  1. 转换编译:
    babel-loader:加载 ES2015+ 代码,然后使用 Babel 转译为 ES5
    script-loader:在全局上下文中执行一次 JavaScript 文件(如在 script 标签),不需要解析
    ts-loaderawesome-typescript-loader:像 JavaScript 一样加载 TypeScript 2.0+
    coffee-loader:像 JavaScript 一样加载 CoffeeScript
  2. 样式编译:
    style-loader:将模块的导出作为样式添加到 DOM 中
    css-loader: 解析 CSS 文件后,使用 import 加载,并且返回 CSS 代码
    less-loader: 加载和转译 LESS 文件
    sass-loader:加载和转译 SASS/SCSS 文件
  3. 模板编译:
    markdown-loader: 将 Markdown 转译为 HTML
    react-markdown-loader:使用 markdown-parse parser(解析器) 将 Markdown 编译为 React 组件
  4. 清理测试:
    eslint-loader: PreLoader,使用 ESLint 清理代码
  5. 框架编译:
    vue-loader: 加载和转译 Vue 组件
    angular2-template-loader:加载和转译 Angular 组件

loader特性

  1. 链式传递。
    从右到左编译,第一个loader的编译输出作为第二个loader的输入,最后返回webpack支持的javascript。
    注意:在modules.rules中,use所定义的数组内loader顺序不能错,比如需要编译less文件,use中应该写的是 [ 'style-loader','css-loader','less-loader']。因为loader是链式传递的,less-loader的输出是.css,才可以作为css-loader的输入,如果顺序不对就会报错。

  2. 支持同步和异步。
    第一个 loader 的传入参数只有一个:资源文件(resource file)的内容。compiler 需要得到最后一个 loader 产生的处理结果。这个处理结果应该是 String 或者 Buffer(被转换为一个 string),代表了模块的 JavaScript 源码。另外还可以传递一个可选的 SourceMap 结果(格式为 JSON 对象)。
    如果是单个处理结果,可以在同步模式中直接返回。如果有多个处理结果,则必须调用 this.callback()。在异步模式中,必须调用 this.async(),来指示 loader runner 等待异步结果,它会返回 this.callback() 回调函数,随后 loader 必须返回 undefined 并且调用该回调函数。

  3. loader 接收查询参数。用于对 loader 传递配置。

参考链接:

https://segmentfault.com/a/1190000013761990
https://www.jianshu.com/p/236466fc0033?tdsourcetag=s_pcqq_aiomsg

你可能感兴趣的:(webpack)