lihongxun945/myblog

使用Rollup构建你的JS代码

lihongxun945 opened this issue · 0 comments

很多人知道 vue 等框架的JS代码是用 rollup 编译的,那么 rollup 是什么呢,它和 webpack 有什么异同?如果你也有这个疑惑,那么这篇文章正好可以解答。

Rollup 是什么

Rollup 本身(不包含任何插件的情况下)只是一个模块语法的转换工具,他可以把 ES6 的模块语法编译成不同的语法:

  • cjs 在node中使用的CMD语法
  • iife 直接在浏览器中运行
  • amd requirejs 的语法
  • umd 兼容 amdcmd

举个例子,我们有用 ES6 模块语法编写的代码如下:

foo.js

export default 'Hello world!'

main.js

import foo from './foo.js'

export default function () {
  console.log(foo)
}

显然ES6的模块语法无法在node中运行,我们使用rollup用这个命令进行打包:

rollup src/main.js -f cjs

打包出的结果如下:

'use strict';

var foo = 'Hello world!';

function main () {
  console.log(foo);
}

module.exports = main;

可以看到rollup做了两件事:

  • ES6 模块语法编译成了 node 的语法
  • 把两个文件的代码打包成了一份。

这就是Rollup本身做的所有事情,是不是很简单明了?

那么会有童鞋要问了,这也太简单了吧?如果我们需要编译 es6/7 中的其他语法呢?

如何处理 ES6/7 等新的JS语法

Rollup本身做的非常精简,任何除了上面讲到的功能外的其他功能,都需要插件来实现,比如我们要把 ES6 中的箭头函数编译一下,就需要安装额外的插件。

把前面的代码稍微改一下,假设我们有如下代码:

foo.js

export default () => {
  return 'Hello world!'
}

main.js

import foo from './foo.js'

export default function () {
  console.log(foo())
}

那么我们打包成 cjs 之后变成了这样:

'use strict';

var foo = () => {
  return 'Hello world!'
};

function main () {
  console.log(foo);
}

module.exports = main;

可以看到正如我们前面所说的,箭头函数根本不会被编译,因为 rollup 默认只会编译模块语法,其他语法他是不管的。为了编译 箭头函数等其他 es6/7 的语法,我们需要一个插件 rollup-plugin-babel

我们在 rollup.config.js 中进行如下配置(这里省略了.babelrc 的配置):

// rollup.config.js
import babel from 'rollup-plugin-babel'

export default {
  input: 'src/main.js',
  output: {
    file: 'bundle.js',
    format: 'cjs'
  },
  plugins: [
    babel()
  ]
}

那么打包出来的代码就变成这样了:

'use strict';

var foo = (function () {
  return 'Hello world!';
});

function main () {
  console.log(foo);
}

module.exports = main;

可以看到其中的箭头函数已经被转成了function

Tree shaking

我们在webpack源码解析 中提到过,webpack本身其实进行 tree-shaking 优化,他只负责把无用的exports删除,最终是由 uglify 完成的摇树优化。

我们都知道Webpack 的treeshaking其实是从 rollup 中 借鉴 来的,而rollup原生就实现了 tree shaking。如果我们把上面的代码稍微做一点修改,改成这样:

foo.js

export const foo = () => {
  return 'Hello world!'
}
export const bar = () => {
  return 'Hello world!'
}

main.js

import {foo} from './foo.js'

export default function () {
    console.log(foo())
}

可以看到其中的 bar 函数被直接删除了。

如何在我的项目中使用Rollup

Rollup 官方提供了两个示例项目 https://github.com/rollup/rollup-starter-apphttps://github.com/rollup/rollup-starter-lib。一个项目是开发JS框架,一个是我们正常的项目。

rollup-starter-lib 重点是展示如何把你的代码打包成不同的版本,以适应不同的环境。这个项目中打包成了三种模块语法: es, cjsumd
rollup-starter-app 重点是展示如何打包你的项目以在浏览器中运行。这个项目会把代码打包成 iife 模式,也就是把你的代码打包成一个自执行函数。另外还使用了 uglify 压缩代码,以及可以生成sourcemap

和 webpack 的区别

在Rollup官方提供的例子中我们就可以看出,Rollup(包括他的插件)做的仅仅是JS的编译打包工作,这和webpack是有本质区别的。webpack是一个通用的前端资源打包工具,它不仅处理JS,也可以通过loader来处理 CSS、图片、字体等各种前端资源,还提供了 hot reload 等方便前端项目开发的功能。如果不是开发一个JS框架,webpack显然会是一个更好的选择。

如果说相同点,Rollup和Webpack的核心都是处理JS,他们都会解析JS的语法树,然后分析模块依赖。如果对webpack的工作原理不了解,也可以参见我之前写的系列博客 webpack源码解析