rollup从0到1

作者: copyLeft | 来源:发表于2021-06-23 11:03 被阅读0次

    目的

    开发基于 typescript ES6 语法, 使用jest eslint 为校验或测试的npm包。 因为需要使用到 ts, 模块化,所以就存在模块编译打包的问题, 现有的打包工具中,webpack , Parcel 更偏向多类型资源 的web应用打包, 对于纯粹的npm工具包来说 rollup 更简单实用, 这里记录rollup的基础使用流程。

    概述

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

    背景

    当期rollup 版本为 2.52.1

    安装

    
    // 全局安装
    npm i -g rollup
    // 本地安装
    npm i -D rollup
    
    

    简单例子

    目录结构

    • root
      • src
      • main.js
      • utils.js
    // main.js
    import { call } from './utils'
    call('show me')
    // utils.js
    export function call(...args){
      console.log(...args)
    }
    
    

    命令行打包构建

    rollup -i src/main.js -o lib/main.js
    // -i 入口文件地址
    // -o 打包后出入目录
    

    打包后的文件

    function call(...args){
      console.log(...args);
    }
    
    call('show me');
    // 可以看到rollup 将两个包的内容都合并到了一个文件夹中
    

    package 配置本地打包命令

    如果我们不希望输入过长的命令行参数或者rollup 为本地安装时,我们可以通过设置package命令解决.

    {
      'script': {
        'build': 'rollup -c rollup.config.js', // 使用配置文件构建
        'dev': 'rollup -c rollup.config.js -w', // 开启实时监控
      }
    }
    

    基础命令

    • -c 指定配置文件
    • -w 监听文件变化,实时构建
    • -i 入口文件
    • -o 输出路径
    • -n 模块名称
    • -m 开启sourcemap

    使用配置文件 rollup.config.js

    在根目录新建文件rollup.config.js , 使用 -c 命令设置rollup配置的文件路径。

    // rollup.config.js
    export default {
      input: 'src/main.js',
      output: {
        name: 'rollup-pkg',
        file: 'lib/main.js',
        format: 'cjs'
      }
    }
    

    基础配置入门

    • input 打包入口
    {
      input: 'src/main.js'
    }
    
    • output 输出配置
    {
     output: {
        // 包名称
        name: 'rollup-pkg',
        // 包类型
        format:'umd',
        // 输出路径
        file: 'lib/main.js',
      }
    }
    
    • plugins 插件,提供扩展功能, 例如: babel ,typescript 转换等
    import pluginResolve from '@rollup/plugin-node-resolve'
    import pluginCommonjs from '@rollup/plugin-commonjs'
    {
      plugins: [
        // 外部依赖查询
        pluginResolve(),
        // commonjs 转换
        pluginCommonjs()
      ]
    }
    
    • external 外链, 忽略部分依赖
    {
       external: ['vue']
    }
    
    • globals 全局模块, 为类似 jquery 挂载在全局对象上的模块指定挂载点
    globals: {
      jquery: '$'
    }
    

    配置进阶

    多类型输出

    output 可以接收配置数组, 打包输入多种形式的结果文件

    {
      output: [
        {
          // umd
          name: 'pks',
          file: 'lib/main.umd.js',
          format: 'umd'
        },
        {
          // esm
          name: 'pks',
          file: 'lib/main.esm.js',
          format: 'esm'
        }
      ]
    }
    // 输出后的文件目录
    // lib
    // - main.umd.js
    // - main.esm.js
    

    独立plugins 配置

    {
      plugins: [....],
      output: [
        {
          ...
          // 为某一输入指定独立的plugins
          plugings: [pluginStrip()]
        }
      ]
    }
    
    

    sourcemap、sourcemapFile

    {
      output: {
         ...
        sourcemap: true // 是否生成sourcemap
        sourcemapFile: '' // sourcemap 输出地址
      }
    }
    

    banner、 footer 文件首尾插入内容

    {
      output: {
         // 插入版本号
         banner: '/* my-library version: v4.1.1 */',
         footer: '/* author copy-left */'
      }
    }
    

    配置列表

    导出配置可以为列表, 同时构建多个包

    export default [
      // 第一组配置, 输出到 lib/ 目录
      {
        input: 'src/main.ts',
        plugins: [
          pluginResolve({
            extensions: ['.js', '.jsx', '.ts', '.tsx'],
          }),
          pluginCommonjs(),
          pluginEslint({
            throwOnError: true,
            throwOnWarning: false,
            include: ['src/**'],
            exclude: ['node_modules/**']
          }),
          pluginTypescript2({
            clean: true,
            tsconfig: './tsconfig.json'
          })
        ],
        output: [
          {
            name: 'roll',
            file: 'lib/main.umd.js',
            format: 'umd'
          },
        ],
      },
      // 第二组配置, 输出到 dist/ 目录
      {
        input: 'src/index.ts',
        plugins: [
          pluginResolve({
            extensions: ['.js', '.jsx', '.ts', '.tsx'],
          }),
          pluginCommonjs(),
          pluginEslint({
            throwOnError: true,
            throwOnWarning: false,
            include: ['src/**'],
            exclude: ['node_modules/**']
          }),
          pluginTypescript2({
            clean: true,
            tsconfig: './tsconfig.json'
          })
        ],
        output: [
          {
            name: 'roll',
            file: 'dist/main.esm.js',
            format: 'esm'
          },
        ],
      }
      
    

    watch 配置项

    {
      // 包含目录
      include: 'src/**',
      // 忽略目录
      exclude: 'node_modules' 
    }
    

    常用插件 - Plugins

    @rollup/plugin-node-resolve

    模块查询,告诉rollup 如何查询node_modules内的依赖模块。

    • 使用
    import pluginResolve from '@rollupplugin-node-resolve'
    {
      plugins: [ pluginResolve({...options}) ]
    }
    
    • options
    {
      // 入口匹配
      exportConditions: ['default', 'module', 'import'],
      // 是否为浏览器环境, false 时将忽略所有浏览器属性
      browser: false,
      // 模块查询目录
      moduleDirectories: ['./src'],
      // 强制定位到根节点的 `node_modules` 包, 防止同类包的多次绑定
      dedupe: [],
      // 可操作的文件类型
      extensions: ['.js', '.jsx', '.ts', '.tsx'],
      // 限制包的查询路径范围
      jail: ['/'],
      // 用于扫描的属性?
      mainFields: ['browser', 'jsnext:main', 'module', 'main'],
      // 是否只处理断言为 ES2015 的模块
      modulesOnly: false,
      // 只查询匹配模式的路径, 未匹配的模块将作为外部模块
      resolveOnly: ['batman', /^@batcave\/.*$/],
      // 模块根目录, 配合 dedupe 属性使用
      rootDir: process.cwd(),
      // 忽略package 中的 sideEffects 设置
      ignoreSideEffectsForRoot: false,
    }
    
    • 实战使用比对
    // main.js
    import dayjs from 'dayjs'
    import { call } from './utils'
    call(dayjs().format('YYYY-MM-DD'))
    // 未使用,ES模式打包结果
    import dayjs from 'dayjs';
    
    
    function call(...args){
      console.log(...args);
    }
    
    
    call(dayjs().format('YYYY-MM-DD'));
    
    
    // 使用后,ES模式打包结果
    var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
    
    
    function createCommonjsModule(fn, module) {
        return module = { exports: {} }, fn(module, module.exports), module.exports;
    }
     // 引入dayjs包
    var dayjs_min = createCommonjsModule(.....);
    
    
    function call(...args){
      console.log(...args);
    }
    
    
    call(dayjs_min().format('YYYY-MM-DD'));
    
    

    @rollup/plugin-commonjs

    将commonjs模块转换为 ES6 模块, 当我们导入commonjs 包时, commonjs 模块无法直接被rollup解析,需要先转换为ES6 模块。该包配合 @rollup/plugin-node-reslove 来正确处理外部依赖的引入问题

    • 使用
    import pluginCommonjs from '@rollup/plugin-commonjs'
    {
      plugins: [pluginCommonjs()]
    }
    
    • options
    {
      // 动态引入处理,为需要动态引入的模块,创建模拟commojs环境
      dynamicRequireTargets: [
         // 需要处理的文件
         'node_modules/logform/*.js',
         // ! 标记不需要处理的文件
         '!node_modules/logform/index.js',
      ],
      // 忽略某些文件
      exclude: [],
      // 包含某些文件
      include: [],
      // 导入其他非js扩展文件
      extensions: ['.js'],
      // 忽略全局对象
      ignoreGlobal: false,
      // 是否生成 sourceMap
      sourceMap: true,
      // 对于同时使用 es6 和 commonjs require 的情况,是否使用混合模式
      transformMixedEsModules: false,
       // 需要忽略的 require
      ignore: [(id) => id !== ''],
      ignoreTryCatch: false,
      ignoreDynamicRequires: false,
      // 定义转换后的包引入写法, 例如: const foo = require('foo'); 转换为 import foo from 'foo';
      esmExternals: false,
      // default 默认导入的处理方式
      defaultIsModuleExports: 'auto',
      // 处理 require 引入返回值
      requireReturnsDefault: false
    }
    
    

    @rollup/plugin-eslint

    引入eslint 规则校验, 如果根目录包含.eslintrc.* 配置文件, 将被自动加载到配置中,
    这里需要注意插件的引入位置, 应在其他编译,转换插件之前。 例如: pluginEslint(...) pluginTypescript2(...)。
    保证eslint 处理的是源码,而非编译后的转换代码。

    • 使用
    import pluginEslint from '@rollup/plugin-eslint'
    {
      plugins: [
        pluginEslint({
          fix: true,
          throwOnError: true,
          throwOnWarning: true,
        })
      ]
    }
    
    • options
    {
      // 是否自动格式化
      fix: false,
      // 显示错误提示
      throwOnError: false,
      // 显示警告提示
      throwOnWarning: false,
      // 包含文件
      include: [],
      // 忽略文件
      exclued: [],
      // 格式化处理函数
      formatter: ''
    }
    
    

    rollup-plugin-typescript2

    typescript 转换

    • 使用
    import pluginTypescript from 'rollup-plugin-typescript2'
    {
      plugins: [
        pluginTypescript({
          tsconfig: './src/tsconfig.json' // 引入本地tsconfig.json
        })
      ]
    }
    
    • options
    {
      // 工作目录
      cwd: process.cwd(),
      // 默认tsconfig 配置
      tsconfigDefaults: {...},
      // tsconfig配置路径
      tsconfig: './src/tsconfig.json',
      // 覆盖 tsconfig,  优先级 tsconfigOverride > tsconfig > tsconfigDefaults
      tsconfigOverride:{...},
      // 是否做校验
      check: true,
      // 错误级别;  0: Error 1: Warning 2: Info 3: Debugs
      verbosity: 1,
      // 是否删除旧的构建文件
      clean: false,
      // 缓存地址
      cacheRoot: '',
      // 包含项规则
      include: [ "*.ts+(|x)", "**/*.ts+(|x)" ],
      // 排除项规则
      exclude: [ "*.d.ts", "**/*.d.ts" ],
      // 错误忽略
      abortOnError: true,
      rollupCommonJSResolveHack:false,
      objectHashIgnoreUnknownHack: false,
      // 是否使用tsconfig内的类型文件导出路径
      useTsconfigDeclarationDir:false,
      // 导入无法被映入的ts模块
      typescript: '',
      transformers: ''
    }
    

    @rollup/plugin-babel

    插件将默认加载根目录下的 babel.config.js 配置文件

    • 使用
    import * as pluginBabel from '@rollup/plugin-babel'
    {
       plugins: [
         pluginBabel.babel({
            babelHelpers: 'bundled',
            include: ['src/**'],
            exclude: ['node_modules/**']
         })
      ]
    }
    

    rollup-plugin-terser

    代码压缩

    import pluginTerser from 'rollup-plugin-terser'
    {
      ...
      plugins: [
        pluginEslint({
          throwOnError: true,
          throwOnWarning: true,
          include: ['./src/**'],
        }),
        pluginNodeResolve(),
        pluginCommonjs(),
        pluginTypescript2({
          tsconfig: './tsconfig.es5.json'
        }),
        pluginTerser.terser() // 放在末尾,导出编译后的压缩文件
      ]
    }
    

    官方插件库

    实例DEMO地址

    rollup-learning-demo

    相关文章

      网友评论

        本文标题:rollup从0到1

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