rollup.js

[TOC]

1. 概念

Rollup是一个JavaScript模块打包工具,可以将小块代码编译成大块复杂的代码。开发者可以使用ES2015模块和TypeScript,最终打包成一个独立的可运行在浏览器或者Node.js环境的文件。

2. tree-shaking

Rollup能让打包文件体积很小,因为内部使用了tree-shaking机制。

2.1 概念

tree-shaking是能够在模块的层面上做到打包后的代码只包含被引用并被执行的模块,而不被引用或者不被执行的模块被删除掉,以达到减包的效果。

2.2 处理范围

  • 只能处理模块级别,消除引用但没有使用的模块,不能处理函数级别的冗余;
  • 只能处理JavaScript相关冗余代码,不能处理CSS冗余代码。

2.3 严格模式下不能处理函数级别的冗余的原因

类的新方法可以通过Object.assign()添加到prototype对象中,如:

class Person {
  public name:String
  constructor(name:String) {
    this.name = name
  }

}

Object.assign(Person.prototype,{
  getName() {
    console.log(this.name);
  },
  setName(name:String) {
    this.name = name
  }
})
console.log(Person.prototype);

在严格模式下,类内部的方法是不可枚举的,因为babel会将类内部的方法编译成Object.defineProperty()。因为识别不到类内部的方法是否存在,也就不能知道究竟有没有用到过类内部的方法,所以tree-shaking不能识别类内部的方法是否未被使用而删除掉。

2.4 module特征

  • 只能作为模块顶层的语句出现
  • import的模块名只能是字符串常量
  • 模块依赖关系是确定的,和运行时的状态无关,可以进行可靠的静态分析。

注意:在es6后才开始关注tree-shaking,是因为es6之前的模块化,是通过require引入一个模块,只有运行后才能知道引用了模块里的哪些方法。

import {button,tab} from 'element-ui'
require('elememt-ui')

2.5 例子

singleton/index.ts

var getSingle = function(fn:Function) {
  var result:any
  return function () {
    return result || (result = fn.apply(this,arguments))
  }
}

var getName = function(name:String) {
  console.log(this.name);
}

export {
  getSingle,
  getName
}

main.ts

import {getSingle} from './singleton/index'
import {createDiv} from './singleton/demo'
var createSingleDiv = getSingle(createDiv)
createSingleDiv()

编译后的文件
main.min.js

var getSingle = function getSingle(fn) {
      var result;
      return function () {
          return result || (result = fn.apply(this, arguments));
      };
  };

  var createDiv = function createDiv() {
      var div = document.createElement('div');
      div.innerHTML = '这个是单例模式创建的div';
      document.body.appendChild(div);
      return div;
  };
var createSingleDiv = getSingle(createDiv);
  createSingleDiv();

如图所示,未使用的getName方法在打包后的文件中消失了。

2.6 非严格模式下可以处理函数级别的冗余

在非严格模式下,类内部的方法编译后是直接加在原型链上的,变得可枚举,可以被识别并筛选
但是,不建议使用非严格模式。

3 Rollup工程搭建

3.1 工程目录

|--src //ts相关代码文件夹
|--styles//样式相关文件夹
|--src  //测试用例相关文件夹
|--.babelrc  //babel配置文件
|--jest.config.js //jest配置文件
|--package.json //配置文件
|--rollup.config.js //rollup配置文件
|--tsconfig.json //TypeScript配置文件
|--tslint.json //tslint配置文件

3.2 安装rollup并且创建配置文件

3.2.1 安装rollup

yarn add rollup --save-dev

3.2.2 创建rollup.config.js

export default {
  entry: 'src/main.ts',//入口文件
  dest: 'build/js/main.min.js',//输出文件
  format: 'iife',//输出格式:立即执行函数表达式
  sourceMap: 'inline' //代码映射,方便调试
}

3.2.3 配置babel

3.2.3.1 安装插件
yarn add rollup-plugin-babel babel-preset-latest  --save-dev
3.2.3.2 作用

用于在旧版浏览器或者环境中将es2015+转换为向后兼容的JavaScript版本。

3.2.3.3 babel过程

1.编译:解析代码生成相同的代码
2.转换:所有语法的转换工作都是由插件完成的
3.生成:生成向后兼容的es5

3.2.3.4 .babelrc文件
{
  "presets": [
    ["latest", {
      "es2015": {
        "modules": false
      }
    }]
  ],
  "plugins": [
    "external-helpers"
  ]
}
3.2.3.5 更新rollup.config.js文件
import babel from 'rollup-plugin-babel'
export default {
  entry: 'src/main.ts',
  dest: 'build/js/main.min.js',
  format: 'iife',
  sourceMap: 'inline',
  plugins: [
    babel({
      exclude: 'node_modules/**',
      plugins: ['external-helpers']
    })
  ]
}

3.2.4 配置TypeScript

3.2.4.1 安装TypeScript
yarn add typescript ts-loader rollup-plugin-typescript2 --save-dev
yarn add awesome-typescript-loader --save
3.2.4.2 tsconfig.json文件
{
  "compilerOptions": {
      "sourceMap": true, //代码映射
      "noImplicitAny": true, //强类型检查
      "module": "es2015", //组织代码方式
      "target": "es2015", //编译目标平台
      "allowJs": true, //允许使用js
      "allowSyntheticDefaultImports": true //允许从没有设置默认导出的模块中默认导入。这并不影响代码的显示,仅为了类型检查。
  },
  "include": [
      "./src/**/*"
  ]
}
3.2.4.3 更新rollup.config.js文件
import rollupTypescript from 'rollup-plugin-typescript2'
...
  plugins: [
    ...
    rollupTypescript(),
  ]
...

3.2.5 其他插件

3.2.5.1 rollup-plugin-postcss

rollup中集成PostCSS

3.2.5.2 rollup-plugin-node-resolve

解析node_modules中的模块

3.2.5.3 rollup-plugin-commonjs

转换COMMONJS(通过module.export暴露模块接口,通过require引入模块,特点是同步执行)到ES6 Module(export/import)

3.2.5.4 rollup-plugin-serve

提供静态服务器能力

3.2.5.5 rollup-plugin-replace

可在源码中通过process.env.NODE_ENV用于构建区分Development与Production环境

3.2.5.6 rollup-plugin-uglify

压缩bundle文件

3.2.5.7 rollup-watch

实时监听rollup代码更改,当代码发生变化时,会自动编译文件更新内容。
在配置文件中不需要配置该插件,只需要:

"scripts": {
    "build": "rollup -c",
    "dev": "rollup -c --watch",
    "pro": "SET NODE_ENV=production",
    "run": "npm run pro && npm run build",
    "test": "jest"
  },

3.2.6 完整的rollup.config.js

// Rollup plugins
import babel from 'rollup-plugin-babel'
import resolve from 'rollup-plugin-node-resolve' //解析node_modules中的模块
import commonjs from 'rollup-plugin-commonjs'//转换COMMONJS(通过module.export暴露模块接口,通过require引入模块,特点是同步执行)到ES6 Module(export/import)
import serve from "rollup-plugin-serve"//提供静态服务器能力
import replace from 'rollup-plugin-replace'//可在源码中通过process.env.NODE_ENV用于构建区分Development与Production环境
import uglify from 'rollup-plugin-uglify'//压缩bundle文件
import postcss from 'rollup-plugin-postcss'
// PostCSS plugins
import simplevars from 'postcss-simple-vars'
import nested from 'postcss-nested'
import cssnext from 'postcss-cssnext'
import cssnano from 'cssnano'
import rollupTypescript from 'rollup-plugin-typescript2'

export default {
  entry: 'src/main.ts',
  dest: 'build/js/main.min.js',
  format: 'iife',
  sourceMap: 'inline',
  plugins: [
    postcss({
      plugins: [
        simplevars(),
        nested(),
        cssnext({
          warnForDuplicates: false,
        }),
        cssnano(),
      ],
      extensions: ['.css','.scss'],
    }),
    rollupTypescript(),
    resolve({
      jsnext: true,
      main: true,
      browser: true,
    }),
    commonjs(),
    babel({
      exclude: 'node_modules/**',
      plugins: ['external-helpers']
    }),
    replace({
      exclude: 'node_modules/**',
      ENV: JSON.stringify(process.env.NODE_ENV || 'development'),
    }),
    (process.env.NODE_ENV === 'production' && uglify()),
    serve({
      // Launch in browser (default: false)
      open: true,

      // Show server address in console (default: true)
      verbose: false,

      // Folder to serve files from
      contentBase: '',

      // Multiple folders to serve from
      contentBase: ['build'],

      // Set to true to return index.html instead of 404
      historyApiFallback: true,

      // Options used in setting up server
      host: 'localhost',
      port: 10001
    })
  ],
}

参考文献


  1. 如何使用Rollup打包JavaScript
  2. rollupjs
  3. TypeScript
  4. 你的Tree-Shaking并没什么卵用
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容