Rollup浅应用

77 阅读7分钟

Rollup

概述

Rollup 是一个 JavaScript 模块打包器,可以将小块代码编译成大块复杂的代码,例如 library 或应用程序。Rollup 对代码模块使用新的标准化格式,这些标准都包含在 JavaScriptES6版本中,而不是以前的特殊解决方案,如 CommonJSAMDES6 模块可以使你自由、无缝地使用你最喜爱的 library 中那些最有用独立函数,而你的项目不必携带其他未使用的代码

Webpack和Rollup对比

Webpack

大型SPA项目的模块化构建(web应用)

  • 通过各种Loader处理各种各样的静态资源
  • 通过各种插件Plugins对整体文件进行一些处理
  • Code splitting将公共模块进行提取
  • 提供一个webpack-dev-server,进行本地开发
  • 支持HMR模块热替换

优势

  • 强大的生态插件
  • 面向开发应用的特性支持HMR,按需加载,公共模块提取
  • 简化Web开发的环节,图片自动转base64,资源的缓存

Rollup

Rollup设计之初就是面向ES Module的,构建出结构扁平,性能出众的类库

ES module的规则

  • import只能作为模块顶层的语句出现,不能出现在function里面或是if里面
  • ES import的模块名只能是字符串常量
  • 不管import的语句出现的问题在哪里,在模块初始化的时候所有的import都必须已经导入完成
  • Tree shaking机制

优势

  • 构建高性能的模块文件
  • 编译出来的代码可读性好,内容更小,执行效率更高
  • 配置简单

Rollup是用来构建库还是应用程序?

Rollup 已被许多主流的 JavaScript 库使用,也可用于构建绝大多数应用程序。但是 Rollup 还不支持一些特定的高级功能,尤其是用在构建一些应用程序的时候,特别是代码拆分和运行时态的动态导入 dynamic imports at runtime. 如果你的项目中更需要这些功能,那使用 Webpack可能更符合你的需求

Tree-shaking

除了使用 ES6 模块之外,Rollup 还静态分析代码中的 import,并将排除任何未实际使用的代码。这允许您架构于现有工具和模块之上,而不会增加额外的依赖或使项目的大小膨胀

例如,在使用 CommonJS时,必须导入(import)完整的工具(tool)或库(library)对象

// 使用 CommonJS 导入(import)完整的 utils 对象
var utils = require( 'utils' );
var query = 'Rollup';

// 使用 utils 对象的 ajax 方法
utils.ajax( 'https://api.example.com?search=' + query ).then( handleResponse );

但是在使用 ES6 模块时,无需导入整个 utils 对象,我们可以只导入(import)我们所需的 ajax 函数

// 使用 ES6 import 语句导入(import) ajax 函数
import { ajax } from 'utils';
var query = 'Rollup';
// 调用 ajax 函数
ajax( 'https://api.example.com?search=' + query ).then( handleResponse );

常用配置

在项目中创建一个名为 rollup.config.js 的文件

export default {
  input: 'src/main.js',
  output: {
    file: 'bundle.js',
    format: 'cjs'
  }
};

Input

入口文件地址

output

如果要输出多个,可以是一个数组

output: {
    file: 'bundle.js', // 输出文件
    format: 'cjs,  //  五种输出格式:amd /  es6 / iife / umd / cjs
    name: 'name',  //当format为iife和umd时必须提供,将作为全局变量挂在window(浏览器环境)下:window.A=...
    sourcemap: true,  //生成bundle.map.js文件,方便调试
    globals: {
        'lodash': '_' // 告诉rollup,全局变量_就是lodash
    }
}
format

生成包的格式

  • amd – 异步模块定义,用于像RequireJS这样的模块加载器
  • cjsCommonJS,适用于 NodeBrowserify/Webpack
  • esm – 将软件包保存为 ES 模块文件,在现代浏览器中可以通过 <script type=module> 标签引入
  • iife – 一个自动执行的功能,适合作为<script>标签。(如果要为应用程序创建一个捆绑包,您可能想要使用它,因为它会使文件大小变小。)
  • umd – 通用模块定义,以amdcjsiife 为一体
globals

Object 形式的 id: name 键值对,用于umd/iife包。例如:

import $ from 'jquery';

我们想告诉 Rollup jquery 模块的id等同于 $ 变量

// rollup.config.js
export default {
  ...,
  format: 'iife',
  name: 'MyBundle',
  globals: {
    jquery: '$'
  }
};

/*
var MyBundle = (function ($) {
  // 代码到这里
}(window.jQuery));
*/.

external

两者任一 Function 需要一个 id 并返回 true(外部引用)或 false(不是外部的引用), 或者 Array 应该保留在bundle的外部引用的模块ID

ID应该是:

  1. 外部依赖的名称
  2. 一个已被找到路径的ID(像文件的绝对路径)
// rollup.config.js
import path from 'path';

export default {
  ...,
  external: [
    'lodash', // 告诉rollup不要将lodash打包,而作为外部依赖
    'some-externally-required-library',
    path.resolve( './src/some-local-file-that-should-not-be-bundled.js' )
  ]
};

插件

Babel

如果我们希望将ES6转成ES5的代码,可以在rollup中使用babel

npm install @rollup/plugin-babel @babel/core -D
import babel from '@rollup/plugin-babel';
import { DEFAULT_EXTENSIONS } from '@babel/core';

const plugins = [
    babel({
      exclude: 'node_modules/**', // 防止打包node_modules下的文件
      extensions: [...DEFAULT_EXTENSIONS, '.ts', '.tsx'],
    })
]

配置babel.config.js文件

module.exports = {
    presets: [
        "@babel/preset-env"
    ]
}
@rollup/plugin-node-resolve和@rollup/plugin-commonjs

rollup.js编译源码中的模块引用默认只支持 ES6+的模块方式import/export。然而大量的npm模块是基于CommonJS模块方式,这就导致了大量 npm 模块不能直接编译使用。所以辅助rollup.js编译支持 npm模块和CommonJS模块方式的插件就应运而生。

  • rollup-plugin-node-resolve 插件允许我们加载第三方模块
  • @rollup/plugin-commonjs 插件将它们转换为ES6版本
npm install @rollup/plugin-node-resolve @rollup/plugin-commonjs -D
import commonjs from '@rollup/plugin-commonjs';
import resolve from '@rollup/plugin-node-resolve';

const plugins = [
    commonjs(),
    resolve(),
    ...
]
Postcss

开发项目我们用webpack,开发js类库,rollupwebpack强。开发js类库一般是不写css,如果你要写大量的css,那可能你开发的是项目,优先选择webpackwebpack里也有开发library的配置。

如果你的js类库里还是必不可少要写些css的话,rollup也是有插件编译css

npm install rollup-plugin-postcss postcss -D
import postcss from 'rollup-plugin-postcss';

const plugins = [
  postcss(),
  ...
]
Vue
npm install rollup-plugin-vue@next vue-template-compiler -D
import vue from 'rollup-plugin-vue';

const plugins = [
  vue(),
  ...
]

此时打包后的文件运行可能会报错: "图片自定义高度" height="" width=""

npm install rollup-plugin-replace -D
import replace from 'rollup-plugin-replace';
import vue from 'rollup-plugin-vue';

const plugins = [
  replace({
     'process.env.NODE_ENV': JSON.stringify('production')
  })
  vue(),
  ...
]
Terser
npm install rollup-plugin-terser -D
import { terser } from 'rollup-plugin-terser';


const plugins = [
  terser(),
  ...
]
rollup-plugin-esbuild

esbuild是目前最快的Ts/ES6编译器之一,该插件取代了rollup-plugin-typescript2@rollup/plugin-typescriptrollup-plugin-terser

yarn add esbuild rollup-plugin-esbuild -D
import esbuild from 'rollup-plugin-esbuild'

const plugins = [
    esbuild({
        minify: true,
        target: 'es2018',
        tsconfig: 'tsconfig.json',
    })
]
// 配置tsconfig.json

{
  "compilerOptions": {
    "target": "esnext",
    "useDefineForClassFields": true,
    "module": "esnext",
    "moduleResolution": "node",
    "strict": true,
    "jsx": "preserve",
    "sourceMap": true,
    "resolveJsonModule": true,
    "esModuleInterop": true,
    "lib": [
      "esnext",
      "dom",
      "dom.iterable",
      "scripthost"
    ],
    "allowJs": true,
    "checkJs": true,
    "importHelpers": true,
    "skipLibCheck": true,
    "allowSyntheticDefaultImports": true,
    "noEmit": true,
    "isolatedModules": true,
    "declaration": true,
    "declarationDir": "lib",
    "types": [
      "node"
    ],
  },
  "include": [
    "packages/**/*.ts",
    "packages/**/*.d.ts",
    "packages/**/*.tsx",
    "packages/**/*.vue",
    "types/**/*.d.ts",
    "types/**/*.ts"
  ],
  "exclude": ["node_modules", "**/lib", "**/__tests__/**/*"]
}
别名使用
npm install @rollup/plugin-alias -D
import alias from '@rollup/plugin-alias'

const path = require('path')
const resolveDir = dir => path.join(__dirname, dir)

const plugins = [
    alias({
        entries: [
            { find: '@', replacement: resolveDir('src') }
        ]
    }),
    ...
]
本地服务器
npm install rollup-plugin-serve -D
import serve from 'rollup-plugin-serve';
import replace from 'rollup-plugin-replace';
import vue from 'rollup-plugin-vue';
import typescript from '@rollup/plugin-typescript';
import commonjs from '@rollup/plugin-commonjs';
import resolve from '@rollup/plugin-node-resolve';
import babel from '@rollup/plugin-babel';
import postcss from 'rollup-plugin-postcss';
// import { terser } from 'rollup-plugin-terser';

const output = {
    file: '.temp/bundle.cjs.js',
    format: 'cjs',
    name: 'bundleName',
    sourcemap: true // 配置sourcemap为true,方便调试代码
}

const devPlugins = [
    resolve(),
    replace({
     'process.env.NODE_ENV': JSON.stringify('production')
    })
    vue(),
    typescript(),
    babel({
      exclude: 'node_modules/**',
    }),
    commonjs(),
    postcss(),
    // terser(),
    serve({
      open: true, // 是否打开浏览器
      port: 8080, // 监听哪一个端口
      contentBase: "." // 服务哪一个文件夹
    })
]
热更新

本地服务器有了,但是每次修改代码,还要重新启动才能生效,很不方便,所以需要热更新。

npm install rollup-plugin-livereload -D
import serve from 'rollup-plugin-serve';
import livereload from 'rollup-plugin-livereload';
import replace from 'rollup-plugin-replace';
import vue from 'rollup-plugin-vue';
import typescript from '@rollup/plugin-typescript';
import commonjs from '@rollup/plugin-commonjs';
import resolve from '@rollup/plugin-node-resolve';
import babel from '@rollup/plugin-babel';
import postcss from 'rollup-plugin-postcss';
// import { terser } from 'rollup-plugin-terser';

const devPlugins = [
    resolve(),
    replace({
     'process.env.NODE_ENV': JSON.stringify('production')
    })
    vue(),
    typescript(),
    babel({
      exclude: 'node_modules/**',
    }),
    commonjs(),
    postcss(),
    // terser(),
    serve({
      open: true, // 是否打开浏览器
      port: 8080, // 监听哪一个端口
      contentBase: "." // 服务哪一个文件夹
    }),
    livereload()
]
其他插件
  • @rollup/plugin-json:可以将.json文件转化为ES6模块
  • rollup-plugin-visualizer:可视化分析Rollup捆绑包
  • rollup-plugin-copy:复制文件和文件夹,并具有glob支持