前端进阶(6) - webpack 以外的另一种挑选:rollup

webpack 以外的另一种挑选:rollup

webpack 对前端来说是再熟习不过的东西了,它供应了壮大的功用来构建前端的资本,包含 html/js/ts/css/less/scss ... 等言语剧本,也包含 images/fonts ... 等二进制文件。

实在,webpack 提议之初重要是为了处置惩罚以下两个题目:

  1. 代码拆分(Code Splitting): 能够将运用程序分解成可治理的代码块,能够按需加载,如许用户便可疾速与运用交互,而没必要比及全部运用程序下载和剖析完成才运用,以此构建庞杂的单页运用程序(SPA);
  2. 静态资本(Static Assets): 能够将一切的静态资本,如 js、css、图片、字体等,导入到运用程序中,然后由 webpack 运用 hash 重命名须要的资本文件,而无需为文件 URL 增加 hash 而运用 hack 剧本,而且一个资本还能依靠其他资本。

恰是由于 webpack 具有云云壮大的功用,所以 webpack 在举行资本打包的时刻,就会发生许多冗余的代码(假如你有检察过 webpack 的 bundle 文件,便会发明)。

比方,把 export default str => str; 这段代码用 webpack 打包就会获得下面的结果:

/******/ (function(modules) { // webpackBootstrap
/******/     // The module cache
/******/     var installedModules = {};
/******/
/******/     // The require function
/******/     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;
/******/     }
/******/
/******/
/******/     // expose the modules object (__webpack_modules__)
/******/     __webpack_require__.m = modules;
/******/
/******/     // expose the module cache
/******/     __webpack_require__.c = installedModules;
/******/
/******/     // define getter function for harmony exports
/******/     __webpack_require__.d = function(exports, name, getter) {
/******/         if(!__webpack_require__.o(exports, name)) {
/******/             Object.defineProperty(exports, name, {
/******/                 configurable: false,
/******/                 enumerable: true,
/******/                 get: getter
/******/             });
/******/         }
/******/     };
/******/
/******/     // getDefaultExport function for compatibility with non-harmony modules
/******/     __webpack_require__.n = function(module) {
/******/         var getter = module && module.__esModule ?
/******/             function getDefault() { return module['default']; } :
/******/             function getModuleExports() { return module; };
/******/         __webpack_require__.d(getter, 'a', getter);
/******/         return getter;
/******/     };
/******/
/******/     // Object.prototype.hasOwnProperty.call
/******/     __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
/******/
/******/     // __webpack_public_path__
/******/     __webpack_require__.p = "";
/******/
/******/     // Load entry module and return exports
/******/     return __webpack_require__(__webpack_require__.s = 0);
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
Object.defineProperty(__webpack_exports__, "__esModule", { value: true });

/* harmony default export */ __webpack_exports__["default"] = (str => str);


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

这在以下的一些情境中就不太高效,须要追求更好的处置惩罚方案:

  1. 须要 js 高效运转。由于 webpack 对子模块定义和运转时的依靠处置惩罚(__webpack_require__),不仅致使文件体积增大,还会大幅拉低机能;
  2. 项目(特别是类库)只要 js,而没有其他的静态资本文件,运用 webpack 就有点大才小用了,由于 webpack bundle 文件的体积略大,运转略慢,可读性略低。

在这类情况下,就想要追求一种更好的处置惩罚方案,这便是 rollup.

如今已经有许多类库都在运用 rollup 举行打包了,比方:react, vue, preact, three.js, moment, d3 等。

1. 东西

装置

npm i -g rollup          # 全局装置

npm i -D rollup          # 当地装置

运用

rollup -c                # 运用一个设置文件,举行打包操纵

更多细致的用法,参考 rollup.js – command-line-flags.

2. 设置

rollup 的设置与 webpack 的设置相似,定义在 rollup.config.js 文件中,比方:

// rollup.config.js
export default {
  input: 'src/index.js',
  output: {
    file: 'bundle.js',
    // amd, cjs, esm, iife, umd, system
    format: 'cjs'
  }
};

经常使用的几个设置项:

  1. input: 源码进口文件,平常是一个文件,如 src/index.js
  2. output: 定义输出,如文件名,目的目次,输出模块范式(es6, commonjs, amd, umd, iife 等),模块导出称号,外部库声明,全局变量等。
  3. plugins: 插件,比方 rollup-plugin-json 能够让 rollup 从 .json 文件中导入 json 数据。

更多细致的设置,参考 rollup.js – configuration-files.

3. rollup 与 webpack 对照

先拿段代码来来看看他们打包以后各自是什么结果。

源代码

# 目次
|-- src/
    |-- index.js
    |-- prefix.js
    |-- suffix.js

    
# prefix.js
const prefix = 'prefix';

export default str => `${prefix} | ${str}`;
    
    
# suffix.js
const suffix = 'suffix';

export default str => `${str} | ${suffix}`;


# index.js
import prefix from './prefix';
import suffix from './suffix';

export default str => suffix(prefix(str)); 

设置

# webpack.config.js
module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'dist/webpack.bundle.js',
    library: 'demo',
    libraryTarget: 'umd'
  }
};


# rollup.config.js
export default {
  input: 'src/index.js',
  output: {
    file: 'dist/rollup.bundle.js',
    name: 'demo',
    format: 'umd'
  }
};

运转

# webpack 打包
webpack


# rollup 打包
rollup -c

webpack.bundle.js

(function webpackUniversalModuleDefinition(root, factory) {
    if(typeof exports === 'object' && typeof module === 'object')
        module.exports = factory();
    else if(typeof define === 'function' && define.amd)
        define([], factory);
    else if(typeof exports === 'object')
        exports["demo"] = factory();
    else
        root["demo"] = factory();
})(typeof self !== 'undefined' ? self : this, function() {
return /******/ (function(modules) { // webpackBootstrap
/******/     // The module cache
/******/     var installedModules = {};
/******/
/******/     // The require function
/******/     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;
/******/     }
/******/
/******/
/******/     // expose the modules object (__webpack_modules__)
/******/     __webpack_require__.m = modules;
/******/
/******/     // expose the module cache
/******/     __webpack_require__.c = installedModules;
/******/
/******/     // define getter function for harmony exports
/******/     __webpack_require__.d = function(exports, name, getter) {
/******/         if(!__webpack_require__.o(exports, name)) {
/******/             Object.defineProperty(exports, name, {
/******/                 configurable: false,
/******/                 enumerable: true,
/******/                 get: getter
/******/             });
/******/         }
/******/     };
/******/
/******/     // getDefaultExport function for compatibility with non-harmony modules
/******/     __webpack_require__.n = function(module) {
/******/         var getter = module && module.__esModule ?
/******/             function getDefault() { return module['default']; } :
/******/             function getModuleExports() { return module; };
/******/         __webpack_require__.d(getter, 'a', getter);
/******/         return getter;
/******/     };
/******/
/******/     // Object.prototype.hasOwnProperty.call
/******/     __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
/******/
/******/     // __webpack_public_path__
/******/     __webpack_require__.p = "";
/******/
/******/     // Load entry module and return exports
/******/     return __webpack_require__(__webpack_require__.s = 0);
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
Object.defineProperty(__webpack_exports__, "__esModule", { value: true });
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__prefix__ = __webpack_require__(1);
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__suffix__ = __webpack_require__(2);



/* harmony default export */ __webpack_exports__["default"] = (str => Object(__WEBPACK_IMPORTED_MODULE_1__suffix__["a" /* default */])(Object(__WEBPACK_IMPORTED_MODULE_0__prefix__["a" /* default */])(str)));


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

"use strict";
const prefix = 'prefix';

/* harmony default export */ __webpack_exports__["a"] = (str => `${prefix} | ${str}`);


/***/ }),
/* 2 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
const suffix = 'suffix';

/* harmony default export */ __webpack_exports__["a"] = (str => `${str} | ${suffix}`);


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

rollup.bundle.js

(function (global, factory) {
    typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
    typeof define === 'function' && define.amd ? define(factory) :
    (global.demo = factory());
}(this, (function () { 'use strict';

    const prefix = 'prefix';

    var prefix$1 = str => `${prefix} | ${str}`;

    const suffix = 'suffix';

    var suffix$1 = str => `${str} | ${suffix}`;

    var index = str => suffix$1(prefix$1(str));

    return index;

})));

实在,你也基础上看出来了,在这类场景下,rollup 的上风在那里:

  1. 文件很小,险些没什么过剩代码,除了必要的 cjs, umd 头外,bundle 代码基础和源码差不多,也没有新鲜的 __webpack_require__, Object.defineProperty 之类的东西;
  2. 实行很快,由于没有 webpack bundle 中的 __webpack_require__, Object.defineProperty 之类的冗余代码;
  3. 别的,rollup 也对 es 模块输出及 iife 花样打包有很好的支撑。

4. 结论

rollup 相对 webpack 而言,要玲珑、干净利落一些,但不具有 webpack 的一些壮大的功用,如热更新,代码支解,大众依靠提取等。

所以,一个不错的挑选是,运用运用 webpack,类库运用 rollup。

5. 后续

更多博客,检察 https://github.com/senntyou/blogs

作者:深予之 (@senntyou)

版权声明:自在转载-非商用-非衍生-坚持签名(创意同享3.0许可证

    原文作者:senntyou
    原文地址: https://segmentfault.com/a/1190000016132385
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞