rollup.js

作者: JunChow520 | 来源:发表于2021-05-08 15:50 被阅读0次

    rollup.js是一个JavaScript模块打包器(Bundler),可将小块代码编译成大块复杂的代码。

    • 专注于ES6模块打包

    模块化

    rollup.js对代码模块化使用了ES6新的标准化格式,而非之前特殊的解决方案,比如CommonJS和AMD。

    模块化 描述 加载
    IIFE 自执行函数 通过<script>标签加载
    AMD 浏览器(Browser)的模块规范 通过RequireJS加载
    CommonJS Node服务端模块规范 通过Webpack加载
    UMD 兼容IIFE、AMD、CJS三种模块规范 -
    ESM ES2015 Module规范 可用Webpack、Rollup加载

    与Webpack偏向于应用打包定位不同,rollup.js更专注于JavaScript类库打包。Webpack对于代码分割和静态资源导入有着先天优势,并支持热模块替换(HRM)。rollup.js不支持代码拆分(Code Splitting)和运行时态加载(Dynamic Import)特性。

    开发应用时可优先选择Webpack,rollup.js对于代码的Tree-shaking和ES6模块有着算法优势上的支持,若项目只需要打包一个简单的bundle包,并基于ES6模块开发则优先考虑使用rollup.js。其实Webpack2.x开始支持Tree-Shaking,并在使用babel-loader的情况下可支持ES6 Module的打包。

    特性优势

    • Tree Shaking:自动移除未使用的代码,输出更小的文件。
    • Scope Hoisting:所有模块构建在一个函数内,执行效率更高。
    • Config:配置文件支持通过ESM模块格式书写
    • 一次输出多种格式
    • 文档精简

    Tree-shaking

    Tree-shaking指的是移除JavaScript上下文中未引用代码,它依赖于ES2015模块系统中的静态结构特性,比如importexport。静态结构的import类似变量引用,无需执行代码,编译时即可确定它是否引用到。若没有引用则不会将该段代码打包进来。

    工作原理

    rollup.js可将自己编写的JavaScript代码与第三方模块打包在一起形成一个文件,该文件可以是一个库(Library)或一个应用(App),打包过程中可应用各类插件实现特定功能。

    Rollup打包原理

    rollup.js默认采用ES模块标准,可通过rollup-plugin-commonjs插件是指支持CommonJS标准。

    环境检测

    rollup.js依赖于Node.js

    $ node -v
    v16.0.0
    $ npm -v
    7.10.0
    

    全局安装rollup.js

    $ npm view rollup
    $ npm i -g rollup
    

    环境搭建

    创建项目

    $ mkdir tsr && cd tsr
    

    初始化Node.js项目,生成package.json项目依赖包配置文件。

    $ npm init -y
    

    项目目录结构

    文件 描述
    src 源文件目录
    dist 编译后的文件目录
    package.json Node.js项目依赖包配置文件
    tsconfig.json TypeScript配置文件,设置TypeScript编译选项。

    package.json

    Node.js中的模块(Module)是一个库或框架,同时也是一个Node.js项目。Node.js项目遵循模块化的架构,因此创建并初始化一个Node.js项目实际上也创建了一个模块,此模块的描述文件即package.json,又称为项目的依赖包管理文件。

    修改包配置文件package.json

    $ vim package.json
    
    {
      "name": "tsr",
      "version": "1.0.0",
      "main": "lib/index.js",
      "module": "lib/index.esm.js",
      "browser": "lib/index.umd.js",
      "license": "MIT",
      "scripts": {
        "build": "rollup -c",
        "dev": "rollup -c -w"
      },
      "devDependencies": {
        "@types/node": "^15.0.2",
        "rollup": "^2.47.0",
        "rollup-plugin-cleandir": "^1.0.0",
        "rollup-plugin-commonjs": "^10.1.0",
        "rollup-plugin-node-resolve": "^5.2.0",
        "rollup-plugin-typescript2": "^0.30.0",
        "typescript": "^4.2.4"
      }
    }
    
    属性 描述
    name 包名
    version 包的版本号
    description 包的描述信息
    homepage 包的官网URL
    author 包的作者
    contributors 包的贡献者
    dependencies 生产环境依赖包列表,安装在node_modules目录下。
    devDependencies 开发环境依赖包列表,安装在node_modules目录下。
    repository 包代码的仓库信息,包括type和URL。
    bin 指定内部命令对应的可执行文件的位置

    入口文件

    $ vim package.json
    
    {
      "main": "lib/index.js",
      "module": "lib/index.esm.js",
      "browser": "lib/index.umd.js",
      "typings": "types/index.d.ts",
    }
    
    属性 描述 限制
    main CommonJS入口文件 browser环境和node环境均可使用
    module 定义NPM包ESM规范的入口文件 browser环境和node环境均可使用
    browser 定义NPM包在browser环境下的入口文件 仅browser环境可用
    typings TypeScript入口文件 IDE环境可用
    "main": "lib/index.js"
    

    main包的主入口文件地址,定义引用依赖的文件地址,不同环境下引入包时会加载main字段中指定的文件,默认是模块根目录下的index.js文件。

    "module": "lib/index.esm.js"
    

    Rollup最早提出了pkg.module的概念,早期NPM包都是基于CommonJS规范,当require("package")时会根据package.jsonmain字段去查找入口文件。

    从ES2015开始,JavaScript拥有了ES Module,相较于之前的模块化方案更为优雅,ESM也是官方标准的JS规范。CommonJS模块化是一种特殊的传统格式,在ESM提出前作为暂时的解决方案。由于CommonJS规范的包都是以main字段表示入口文件,ESM如果也使用main字段会对使用者造成困扰,因此Rollup使用了另一个字段module

    "typings": "types/index.d.ts",
    
    • typings字段是为了方便IDE识别、编辑、智能提示JavaScript语法的工具。
    • typings入口文件中的代码只是为编辑器智能提示而服务,真正执行程序并不会使用。

    TypeScript

    项目安装TypeScript

    $ npm i -D typescript
    
    $ npm ls typescript
    tsr@1.0.0 F:\TS\project\tsr
    └── typescript@4.2.4
    
    $ tsc --version
    Version 4.2.4
    

    tsconfig.json

    初始化生成TypeScript编译器配置文件,当某目录下存在tsconfig.json文件则认为该目录为TypeScript项目的根目录。

    $ tsc --init
    message TS6071: Successfully created a tsconfig.json file.
    

    tsconfig.json配置文件主要分为两部分:指定待编译文件和定义编译选项

    $ vim tsconfig.json
    
    {
      "compilerOptions": {
    
        "target": "esnext",
        "lib": ["dom","esnext"],
    
        "module": "esnext",
        "moduleResolution": "node",
    
        "declaration": false,
        "declarationMap": false,
    
        "sourceMap": true,
        "outDir": "./lib/",
        "removeComments": true,
    
        "strict": true,
        "noImplicitAny": false,
    
        "baseUrl": "./",
        "esModuleInterop": true,
    
        "skipLibCheck": true,
        "forceConsistentCasingInFileNames": true,
    
        "allowJs": true,
        "resolveJsonModule": true
      },
      "include": ["src"]
    }
    

    编译选项compilerOptions

    "target": "esnext"
    
    • target用于指定编译后的JavaScript目标版本
    • esnext是一个JavaScript库,可将ES6草案规范语法转换为当前JavaScript语法。
    "lib": ["dom","esnext"]
    

    lib选项表示编译过程中需引入的库文件,指定要包含在编译中的库文件。

    库文件 描述
    dom DOM运行环境
    esnext ES6转换为ES5的环境

    lib没有指定默认注入的库的列表则默认注入的库为

    编译目标(target) 注入库(lib)
    ES5 DOM,ES5,ScriptHost
    ES6 DOM,ES6,DOM.Iterable,ScriptHost
    "module": "esnext"
    
    • module选项用于指定模块化规范,即生成哪种模块系统代码。
    模块系统 描述
    None -
    CommonJS -
    AMD -
    System -
    UMD -
    ES6 -
    ES2015 -
    "moduleResolution": "node"
    
    • moduleResolution用于指定模块解析策略,拥有两种可选策略nodeclassic
    • 模块解析是指编译器在查找导入模块内容时所遵循的流程

    编译器会尝试定位导入模块的文件,编译器会遵循两种策略之一:Classic和Node,这些策略会告知编译器到哪里去查找目标模块。

    import Entry from "./components/Entry"
    import { DefaultHeaders } from "../constants/http"
    import * as $ from "jQuery"
    import { Component } from "@angular/core"
    
    解析策略 描述
    classic TS之前默认的解析策略,为向后兼容而保留。
    node 运行时模仿Node.js模块解析机制
    "declaration": true
    
    • declaration选项用于指定是否在编译时生成相应地*.d.ts声明文件,若为true则表示编译每个.ts文件会自动生成一个.js文件和一个*.d.ts声明文件。
    • declarationallowJs选项不能同时设置为true
    "declarationMap": false
    
    • declarationMap选项用于指定.ts文件编译时是否为其声明文件.d.ts生成.d.ts.map文件
    "sourceMap": false
    
    • sourceMap选项用于指定编译.ts文件时是否生成.map文件

    @types/node

    在Node.js中搭建TypeScript开发环境后,才能使用TypeScript开发Node.js项目。

    TypeScript中无法直接使用Node.js内置模块和第三方模块,无法直接在TypeScript文件中导入模块。根据TypeScript自身机制,需要*.d.ts的声明文件,来说明模块对外公开的方法和属性类型及内容。

    TypeScript2.x以上获取类型声明文件只需使用NPM安装@types/node插件即可实现

    tsconfig.json配置中通过lib指定TypeScript环境为["dom", "esnext]表示采用Node.js环境,此时不存在Node.js环境,需安装@types/node插件来支持。

    $ npm i -D @types/node
    

    安装类型声明后即可直接在.ts文件中导入Node.js内置模块

    $ vim rollup.config.ts
    
    import * as path from "path";
    

    如何在TypeScript中导入本地JSON文件呢?需在tsconfig.json配置文件的编译器选项(compilerOptions)中开启allowJsresolveJsonModule两个选项。

    $ vim tsconfig.json
    
    {
      "compilerOptions": {
        "allowJs": true,
        "resolveJsonModule": true
      }
    }
    
    编译选项 默认值 描述
    allowJs false 是否能在TypeScript文件中引入JavaScript库
    checkJs false 是否检查JavaScript代码合法性
    resolveJsonModule false 是否可以在TypeScript中导入JSON Module

    ts-node

    普通运行TypeScript需先通过tsc命令将.ts文件编译为.js文件后才能使用node命令运行node xxx.jsts-node包装了node可直接运行TypeScript代码,使用ts-node仅需ts-node xxx.ts即可直接运行TypeScript文件。

    $ npm i -g ts-node
    

    例如:使用ts-node命令执行TypeScript文件

    $ ts-node index.ts
    

    Rollup

    项目安装rollup打包工具

    $ npm i -D rollup
    $ npm ls rollup
    tsr@1.0.0 F:\TS\project\tsr
    └── rollup@2.47.0
    $ rollup -v
    rollup v2.47.0
    
    $ rollup --help
    
    rollup version 2.47.0
    
    命令参数 完整参数 描述
    -i --input <filename> 要导报的文件
    -o --file <output> 输出的文件,若无则直接输出到控制台。
    -f --format <format> 输出的文件类型(amd、cjs、esm、life、umd)
    -e --external <ids> 将模块ID的逗号分割列表排除
    -g --globals <pairs> module ID:Global键值对形式
    -n --name <name> 生成UMD模块的名字
    -h --help 输出帮助信息
    -m --sourcemap 生成SourceMap信息
    --amd.id - AMD模块的ID,默认为匿名函数。
    --amd.define - 使用Function来代替define
    -w --watch 监视文件打包与重新打包时的变化

    自定义脚本命令

    • NPM允许在package.jsonscripts字段中自定义脚本命令
    • scripts字段是一个对象,每个属性对应一条脚本。
    • 自定义脚本命令使用npm run执行脚本
    $ vim package.json
    
    {
      "scripts": {
        "build": "rollup -c",
        "dev": "rollup -c -w"
      }
    }
    

    rollup.config.js

    Rollup的配置文件是可选的,位于根目录下的rollup.config.js,是一个ES6模块对外暴露一个对象。

    $ vim rollup.config.js
    
    import * as path from "path";
    import {cleandir} from "rollup-plugin-cleandir";
    import typescript from "rollup-plugin-typescript2";
    import commonjs from "rollup-plugin-commonjs";
    import nodeResolve from "rollup-plugin-node-resolve";
    
    import * as pkg from "./package.json"
    import * as tsconfig from "./tsconfig.json"
    
    const outDir = path.join(__dirname, tsconfig.compilerOptions.outDir)
    
    //配置规则
    export default {
        //入口文件
        input:path.join(__dirname, "src/main.ts"),
        //输出文件
        output:[
            //输出CommonJS规范的代码
            {format:"cjs", name:pkg.name, file:path.join(outDir, "index.js")},
            //输出ESM规范的代码
            {format:"esm", name:pkg.name, file:path.join(outDir, "index.esm.js")}
        ],
        //配置插件
        plugins:[
            //自动读取tsconfig.json
            typescript(),
            //自动清除文件夹
            cleandir(outDir),
            //配置Rollup支持CommonJS规范用以识别CommonJS规范的依赖
            commonjs(),
            //解析node_modules中CommonJS规范的第三方模块
            nodeResolve({customResolveOptions:{moduleDirectory:"node_modules"}})
        ]
    }
    

    配置入口文件打包后输出文件,打包时可指定生成包的格式,打包后可通过<script>标签引入,也可通过import等方式引入作为JavaScript库使用。

    Rollup配置选项

    核心 默认值 描述 命令
    input "/src/main.ts" 设置包的入口点 -i/--input
    output [] 设置待写入的输出文件列表,可用于生成sourcemap。 -

    输出文件选项output

    输出选项 默认值 描述 命令
    format cjs 生成包的格式 -f/--output.format
    name "" 生成包的名称 -n/--name
    file "" 待写入的文件,也可用生成sourcemap -o/--output.file
    sourceMap false 是否生成SourceMap文件 -
    {format:"cjs", name:pkg.name, file:dist("index.js"), sourceMap:false}
    

    生成包的格式format

    格式 描述
    amd 异步模块定义,用于类似RequireJS这样的模块加载器。
    cjs CommonJS,适用于Node.js和Browserify/Webpack打包工具。
    ems 将软件包保存为ES模块文件,现代浏览器可通过<script type="module">标签引入。
    iife 自执行函数,适用于<script>标签。
    umd 通用模块定义,以AMD、CommonJS、IIFE为一体。
    system SystemJS加载器格式

    例如:为不同模块化规范输出不同的打包文件

    $ vim rollup.config.js
    
    import * as path from "path";
    import * as pkg from "./package.json"
    
    const dist = filename => filename!=null ? path.join(path.join(__dirname, "dist"), filename) : path.join(__dirname, "dist")
    
    //配置规则
    export default {
        //输出文件
        output:[
            //输出CommonJS规范的代码
            {format:"cjs", name:pkg.name, file:dist("index.js"), sourceMap:false},
            //输出ESM规范的代码
            {format:"es", name:pkg.name, file:dist("index.esm.js"), sourceMap:false}
        ]
    }
    

    使用Rollup的配置文件

    $ rollup -c
    $ rollup --config
    $ rollup --config rollup.config.js
    

    插件

    Rollup的插件提供了统一的标准接口,通过约定大于配置定义公共配置,注入当前构造结果相关的属性和方法,供开发者实现增删改查操作。

    一个Rollup插件是一个导出了一个函数的包,函数返回了一个对象,对象拥有遵循特定规范的属性和钩子。

    • 插件名称必须以rollup-plugin-开头
    • package.json设置keywordrollup-plugin
    • 插件应被测试,推荐采用mocha和ava。
    • 尽可能使用异步方法

    搜索插件:https://github.com/rollup/awesome

    插件 描述
    rollup 核心包
    typescript2 让Rollup识别TypeScript
    buble 类似babel工具但比babel更轻
    commonjs 将CommonJS转换为ES6模块
    json 将JSON文件转换为ES6模块
    node-resolve 让Rollup能够识别node_modules中的包,引入第三方库默认是无法识别的。
    terser 代码压缩,代码最小化打包。
    filesize 显示打包出来的文件大小
    sourcemaps 生成sourcemaps文件
    cleandir 文件夹清除

    rollup-plugin-typescript2

    $ npm i -D rollup-plugin-typescript2
    

    rollup-plugin-commonjs

    NPM中大多数包是以CommonJS模块的形式出现的,使用前需将CommonJS模块转换为ES2015模块供Rollup处理。

    rollup-plugin-commonjs应该用在其它插件转换自定义模块之前,以防止其他插件改变破坏CommonJS的检查。

    $ npm i -D rollup-plugin-commonjs
    

    rollup-plugin-node-resolve

    rollup-plugin-node-resolve插件用于告知Rollup如何查找外部模块

    $ npm i -D rollup-plugin-node-resolve
    

    rollup-plugin-buble

    buble插件作用是在`rollup.js打包过程中进行代码编译,将ES6+代码编译称为ES2015标准。

    Node.js项目中安装buble插件

    $ npm i -D rollup-plugin-buble
    
    $ npm ls buble
    tsr@1.0.0 F:\TS\project\tsr
    └─┬ rollup-plugin-buble@0.19.8
      └── buble@0.19.8
    

    Rollup配置插件

    $ vim rollup.config.js
    
    import buble from "rollup-plugin-buble"
    
    //配置规则
    export default {
        //配置插件
        plugins:[
            //将ES6+代码编译成ES2015
            buble()
        ]
    }
    

    rollup-plugin-alias

    alias插件提供为模块起别名的功能

    项目中安装alias插件

    $ npm i -D rollup-plugin-alias
    

    为项目添加插件配置

    $ vim rollup.config.js
    
    import alias from "rollup-plugin-alias"
    
    //获取绝对路径
    const pathResolve = p => path.resolve(__dirname, p)
    
    //配置规则
    export default {
        //配置插件
        plugins:[
            //为模块起别名
            alias({"@":pathResolve("src")})
        ]
    }
    

    提供pathResolve函数用于生成绝对路径,引入alias插件需传入一个对象作为参数,对象的key是模块中使用的别名,对象的value是别名对应的真实离苦精。

    rollup-plugin-flow-no-whitespace

    flow插件用于在rollup.js打包过程中清除flow类型检查部分的代码

    rollup-plugin-replace

    replace插件的作用是在Rollup打包时动态地替换代码中的内容

    $ npm i -D rollup-plugin-replace
    

    rollup-plugin-terser

    terser插件用于在Rollup打包过程中实现代码压缩代码实现最小化打包,支持ES模块。

    $ npm i -D rollup-plugin-terser
    

    配置

    $ vim rollup.config.js
    
    import {terser} from "rollup-plugin-terser";
    
    //配置规则
    export default {
        //配置插件
        plugins:[
            //代码压缩
            terser({
                output:{ascii_only:true},//仅输出ASCII字符
                compress:{pure_funcs:["console.log"]}//去除console.log函数
            })
        ]
    }
    

    相关文章

      网友评论

          本文标题:rollup.js

          本文链接:https://www.haomeiwen.com/subject/tygjdltx.html