webpack 以外的另一种挑选:rollup
webpack 对前端来说是再熟习不过的东西了,它供应了壮大的功用来构建前端的资本,包含 html/js/ts/css/less/scss ...
等言语剧本,也包含 images/fonts ...
等二进制文件。
实在,webpack 提议之初重要是为了处置惩罚以下两个题目:
- 代码拆分(Code Splitting): 能够将运用程序分解成可治理的代码块,能够按需加载,如许用户便可疾速与运用交互,而没必要比及全部运用程序下载和剖析完成才运用,以此构建庞杂的单页运用程序(SPA);
- 静态资本(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);
/***/ })
/******/ ]);
这在以下的一些情境中就不太高效,须要追求更好的处置惩罚方案:
- 须要 js 高效运转。由于 webpack 对子模块定义和运转时的依靠处置惩罚(
__webpack_require__
),不仅致使文件体积增大,还会大幅拉低机能; - 项目(特别是类库)只要 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'
}
};
经常使用的几个设置项:
-
input
: 源码进口文件,平常是一个文件,如src/index.js
。 -
output
: 定义输出,如文件名,目的目次,输出模块范式(es6
,commonjs
,amd
,umd
,iife
等),模块导出称号,外部库声明,全局变量等。 -
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 的上风在那里:
- 文件很小,险些没什么过剩代码,除了必要的
cjs
,umd
头外,bundle 代码基础和源码差不多,也没有新鲜的__webpack_require__
,Object.defineProperty
之类的东西; - 实行很快,由于没有 webpack bundle 中的
__webpack_require__
,Object.defineProperty
之类的冗余代码; - 别的,rollup 也对 es 模块输出及 iife 花样打包有很好的支撑。
4. 结论
rollup 相对 webpack 而言,要玲珑、干净利落一些,但不具有 webpack 的一些壮大的功用,如热更新,代码支解,大众依靠提取等。
所以,一个不错的挑选是,运用运用 webpack,类库运用 rollup。
5. 后续
更多博客,检察 https://github.com/senntyou/blogs
版权声明:自在转载-非商用-非衍生-坚持签名(创意同享3.0许可证)