rollup打包自己的js库

3,132 阅读7分钟

rollup 采用 es6 原生的模块机制进行模块的打包构建,rollup 更着眼于未来,对 commonjs 模块机制不提供内置的支持,是一款更轻量的打包工具。rollup 比较适合打包 js 的 sdk 或者封装的框架等,例如,vue 源码就是 rollup 打包的。而 webpack 比较适合打包一些应用,例如 SPA 或者同构项目等等。

  • package.json文件字段详解:
  1. name:包的名称,必须是唯一的,由小写英文字母、数字和下划线组成,不能包含空格。
  2. version:符合语义化版本识别规范的版本字符串主版本号:当你做了不兼容的 API 修改;子版本号:当你做了向下兼容的功能性新增;修订号:当你做了向下兼容的问题修正。
  3. description:包的简要说明。
  4. main:指定包的入口文件,若没有指定,默认找 index.js文件。若包中没有index.js文件,也没有指定 main,就会报错。
  5. scripts:保存一些常用指令,通过npm run [key]的方式运行指令。应用场景:每次执行某个js文件都需要传递参数,并且每次传递的参数都是一样的。那么就可以通过将指令保存到scripts中来简化输入指令的操作。test:如果scripts中的key为test,要想运行test可以不写run,即:npm [key];start:如果scripts中的key为start,要想运行start可以不写run,即:npm [key]。
  6. keywords:关键字数组,通常用于搜索。
  7. author:作者。
  8. license:许可证数组,每个元素要包含type(许可证名称)和url(链接到许可证文本的- 地址)字段。也称为开源协议。
  9. devDependencies:开发环境包的依赖,一个关联数组,由包的名称和版本号组成。
{
    // 发布时候的项目名  必填项  @xxx是代表范围包
    "name": "@xxx/package",
    //发布版本 必填项
    "version": "1.0.0",
    // 项目描述信息,description是字符串,便于用户在npm上搜索到我们的项目
    description: 'xxxxx',
    //包私有,无法发布到npm
    private: true,
    //包的关键字 用于npm搜索
    "keywords": [
      "xxx",
      "xxx"
    ],
    // homepage项目的主页地址
    "homepage": "github.com.xxx",
    // 项目问题反馈的Url或报告问题的邮箱地址,
    "bugs": {
      "email": "",
      "url": ""
    },
    //许可证
    "license": "MIT",
    //作者信息
    "author": {
      "name": "",
      "url": "",
      "email": ""
    },
    // 贡献者信息 array
    "contributors": [
      {
        "name": "",
        "email": "",
        "url": ""
      }
    ],
    // 下载依赖包所包含的文件 指定这个包被install时候有哪些文件 或者说 发布package时,具体那些文件会发布上去
    "files": [
      "es",
      "lib"
    ],
    //主文件,也是项目的入口文件,默认值是项目根目录下的index.js
    "main": "lib/index.js",
    //es6 环境下入口文件
    "module": "",
    //yarn workspace monorepo
    "workspaces":[],
    //确保所有的package具有相同的版本
    "resolutions":{},
    //仓库地址
    "repository": {
      "type": "git",
      "url": "http://.jd.com"
    },
    //可通过 process.env.npm_package_config_port获取到8080
    // 用于添加命令行的环境变量 可以通过输入命令npm config set来修改值
    "config": {
      "port": "8080"
    },
    //包的限制
    "engines": {
      "node": ">=13.14.0",
      "yarn": ">=1.22.0"
    },
    // devDependencies 和 dependencies
    //dependencies,依赖的意思,这些安装包都是程序所依赖的包,需要发布到生产环境的.
    //dev即develop,开发的意思,也就是开发环境下的依赖。,
    // devDependencies中的插件只用于开发环境,不用于生产环境,而dependencies是要发布到生产环境
    "dependencies": {
  
    },
    "devDependencies": {
  
    },
       //相对依赖
      "peerDependencies": {
      },
    //>1.0.2 大于当前版本
    //
    //>=1.0.2 大于等于当前版本
    //
    //<1.0.2 小于当前版本
    //
    //<=1.0.2小于等于当前版本
    //
    //~1.0.2 不低于1.0.2,但不改变大版本号和次要版本号
    //
    //^1.0.2 不低于1.0,2, 但不改变大版本号
    //
    //1.2.x 表示1.2.3 ,1.2.4版本都支持,
    //脚本
    "scripts": {
      "start": "webpack-dev-server --open 'Google Chrome'"
    },
    //发布设置
    "publishConfig": {
      //If present, will replace whatever registry is defined in the configuration when the package is about to be pushed to a remote location
      "registry": "http://registry.mddddd.jd.com",
      //包的访问权限
      "access": "public"
    },
    // typings: TypeScript 的入口文件
    "typings": "lib/index.d.ts",
    // jsdelivr cdn公共库
    "jsdelivr":"lib/index.min.js"
  }
  
  • rollup打包:
  1. 新建项目目录:mkdir roll_up;

  2. 初始化项目工程,对包进行管理:npm init -y; 1652333969(1).png

  3. 全局安装 rollup:npm install -g rollup;

  4. 在 roll_up 下安装 rollup:npm install --save-dev rollup;

1652336005(1).png 5. 创建 rollup 配置文件:在项目根目录 roll_up下新建文件 rollup.config.js,并添加如下代码。

/*
* rollup.config.js:
* 注意: 1.输出的文件类型: amd, cjs, es, iife, umd; 2.当入口文件有 export时, umd格式必须
* 指定 name,这样,在通过<script>标签引入时,才能通过 name访问到 export的内容。
*/

export default {
    input: "src/main.js", // 要打包的文件(打包入口文件)
    output: { // 指定一种输出格式可为对象
        file: "dist/js/main.umd.js", // 输出的文件(如果没有这个参数,则直接输出到控制台)
        format: "umd", // Rollup 输出的文件类型
        name: 'bundle-name' // 生成包名称,代表你的 iife/umd包,同一页上的其他脚本可以访问
                            // 它(iife/umd 没有 name会报错的)。
    }
};   

export default {
    input: "src/main.js",
    output: [
        {
            file: "dist/js/main.umd.js",
            format: "umd",
            name: 'bundle-name'
        },
        {
            file: "dist/js/main.es.js",
            format: "es"
        },
        {
            file: "dist/js/main.cjs.js",
            format: "cjs"
        }
    ]
};   

1652344109(1).png 6. 新建需要打包的文件:在项目根目录 roll_up下新建文件夹 src,并在 src下新建 main.js文件,作为打包入口文件。

/*
* src/main.js:
*/
export var name = '张三';
export function getName() {
    return `获取的名字为:${name}`;
}

1652344517(1).png

  1. 测试打包效果:在控制台项目根目录下运行 rollup -c命令,执行配置文件,进行文件打包,根据 rollup.config.js文件中的配置生成 dist目录并生成相关的格式文件。

1652344933(1).png 1652345292(1).png image.png 8. 测试打包后的文件效果:在项目根目录下新建 example 文件夹,且在文件夹中新建 index.html 文件,在文件中通过 script 的方式引入 umd 格式的打包文件,记住不要添加 type="javascript" 属性,否则报错。代码中通过 rollup.config.js 文件中指定的 name 字段名访问到 export 内容。

/*
* example/index.html:
*/
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="../dist/js/main.umd.js"></script>
</head>
<body>
<script>
const { name, getName } = window["bundle-name"];
console.log(name); // 张三
console.log(getName()); // 获取的名字为:张三
</script>
</body>
</html>

1652346420(1).png

  1. 通过 package.json 配置 rollup 打包命令:在 package.json 文件中的 scripts 对象中添加 dev 字段,并指定执行的命令脚本。
{
  "name": "roll_up",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "dev": "rollup -c -w"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "rollup": "^2.72.1"
  }
}

1652348501.png 10. 压缩代码: 添加 UglifyJS 可以通过移除注上释、缩短变量名、重整代码来极大程度的减少 bundle 的体积大小 —— 这样在一定程度降低了代码的可读性,但是在网络通信上变得更有效率。通过 npm install --save-dev rollup-plugin-uglify 安装 rollup-plugin-uglify 插件(该插件目前不支持 es6,可以用 rollup-plugin-terser 替换),rollup.config.js 配置文件中添加插件配置,执行压缩文件的方法。

/*
* rollup.config.js:
*/
import { uglify } from 'rollup-plugin-uglify';

export default {
    input: "src/main.js",
    output: [
        ... // 省略配置
    ],
    plugins: [
        uglify()
    ]
};   
  1. 使用 babel 将代码编译成 es5:rollup 的模块机制是 ES6 Modules,但并不会对 es6 其他的语法进行编译。因此如果要使用 es6 的语法进行开发,还需要使用 babel 来帮助我们将代码编译成 es5。故,安装 rollup-plugin-babel  ,通过 npm install --save-dev @babel/core @babel/preset-env rollup-plugin-babel@latest 进行安装,项目根目录下创建 .babelrc 配置文件,配置内容如下。rollup.config.js 配置文件中插件配置执行 babel方法。

备注:@babel/core、@babel/preset-env 是 babel 7 必要模块。

/*
* package.json:
*/
{
  "name": "roll_up",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "dev": "rollup -c -w"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "@babel/core": "^7.17.10",
    "@babel/preset-env": "^7.17.10",
    "rollup": "^2.72.1",
    "rollup-plugin-babel": "^4.4.0",
    "rollup-plugin-uglify": "^6.0.4"
  }
}

/*
* .babelrc:
*/
{
    "presets": [
        [
            "@babel/preset-env",
            {
                "modules": false
            }
        ]
    ]
}
import { uglify } from 'rollup-plugin-uglify';
import babel from "rollup-plugin-babel";

/*
* rollup.config.js:
*/
export default {
    input: "src/main.js",
    output: [
        ... // 省略配置
    ],
    plugins: [
        uglify(),
        babel({
            exclude: 'node_modules/**', // 为了避免转译第三方脚本,我们需要设置一个 
        }),                             // exclude的配置选项来忽略掉 node_modules目录。
    ]
};   
  1. 兼容 commonjs:npm 生态已经繁荣了多年,commonjs 规范作为 npm 的包规范,大量的 npm 包都是基于 commonjs 规范来开发的,因此在完美支持 es6 模块规范之前,我们仍旧需要兼容 commonjs 模块规范。
  • rollup 提供了插件rollup-plugin-commonjs ,以便于在 rollup 中引用 commonjs 规范的包。该插件的作用是将 commonjs 模块转成 es6 模块。
  • rollup-plugin-commonjs 通常与 rollup-plugin-node-resolve 一同使用,后者用来解析依赖的模块路径。

可通过 npm install --save-dev rollup-plugin-commonjs rollup-plugin-node-resolve 安装所需插件。

/*
* package.json:
*/
{
  "name": "roll_up",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "dev": "rollup -c -w"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "@babel/core": "^7.17.10",
    "@babel/preset-env": "^7.17.10",
    "rollup": "^2.72.1",
    "rollup-plugin-babel": "^4.4.0",
    "rollup-plugin-commonjs": "^10.1.0",
    "rollup-plugin-node-resolve": "^5.2.0",
    "rollup-plugin-uglify": "^6.0.4"
  }
}

/*
* rollup.config.js:
*/
import { uglify } from 'rollup-plugin-uglify';
import babel from "rollup-plugin-babel";
import resolve from 'rollup-plugin-node-resolve';
import commonjs from 'rollup-plugin-commonjs';

export default {
    input: "src/main.js",
    output: [
        ... // 省略配置
    ],
    plugins: [
        uglify(),
        babel({
            exclude: 'node_modules/**',
        }),
        resolve({
            jsnext: true, // jsnext 表示将原来的 node模块转化成 ES6模块, main和 browser
            main: true,   // 则决定了要将第三方模块内的哪些代码打包到最终文件中。
            browser: true,
        }),
        commonjs(),
    ]
};   
  1. 替换环境变量rollup-plugin-replace 本质上是一个用来查找和替换的工具。它可以做很多事,但对我们来说只需要找到目前的环境变量并用实际值来替代就可以了。(例如:在 bundle 中出现的所有 ENV 将被 "production" 替换)。可以通过 npm install --save-dev rollup-plugin-replace 来安装该插件。
/*
* package.json:
*/
{
  "name": "roll_up",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "dev": "rollup -c -w"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "@babel/core": "^7.17.10",
    "@babel/preset-env": "^7.17.10",
    "rollup": "^2.72.1",
    "rollup-plugin-babel": "^4.4.0",
    "rollup-plugin-commonjs": "^10.1.0",
    "rollup-plugin-node-resolve": "^5.2.0",
    "rollup-plugin-replace": "^2.2.0",
    "rollup-plugin-uglify": "^6.0.4"
  }
}

/*
* rollup.config.js:
* 注意: 1.我们可以添加一个 key:value的配对表,key值是准备被替换的键值,而 value是将要被替换的
* 值。在我们的配置中找到每一个 ENV并用 process.env.NODE_ENV去替换,SON.stringify用来确保值
* 是双引号的,不像 ENV这样。
*/
import { uglify } from 'rollup-plugin-uglify';
import babel from "rollup-plugin-babel";
import resolve from 'rollup-plugin-node-resolve';
import commonjs from 'rollup-plugin-commonjs';
import replace from "rollup-plugin-replace";

export default {
    input: "src/main.js",
    output: [
        ... // 省略配置
    ],
    plugins: [
        process.env.NODE_ENV === "production" && uglify(), // 只在生产环境压缩混淆代码
        babel({
            exclude: 'node_modules/**',
        }),
        resolve({
            jsnext: true,
            main: true,
            browser: true,
        }),
        commonjs(),
        replace({
            ENV: JSON.stringify(process.env.NODE_ENV || "development")
        })
    ]
};   
  1. eslint 检查:通过 npm install --save-dev rollup-plugin-eslint 安装 eslint。具体参考使用rollup打包JS的方法步骤

  2. 完整的项目:

/*
* package.json:
*/
{
  "name": "roll_up",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "dev": "rollup -c -w"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "@babel/core": "^7.17.10",
    "@babel/preset-env": "^7.17.10",
    "rollup": "^2.72.1",
    "rollup-plugin-babel": "^4.4.0",
    "rollup-plugin-commonjs": "^10.1.0",
    "rollup-plugin-node-resolve": "^5.2.0",
    "rollup-plugin-replace": "^2.2.0",
    "rollup-plugin-uglify": "^6.0.4"
  }
}

/*
* rollup.config.js:
*/
import { uglify } from 'rollup-plugin-uglify';
import babel from "rollup-plugin-babel";
import resolve from 'rollup-plugin-node-resolve';
import commonjs from 'rollup-plugin-commonjs';
import replace from "rollup-plugin-replace";

export default {
    input: "src/main.js",
    output: [
        {
            file: "dist/js/main.umd.js",
            format: "umd",
            name: 'bundle-name'
        },
        {
            file: "dist/js/main.es.js",
            format: "es"
        },
        {
            file: "dist/js/main.cjs.js",
            format: "cjs"
        },
    ],
    plugins: [
        uglify(),
        babel({
            exclude: 'node_modules/**',
        }),
        resolve({
            jsnext: true,
            main: true,
            browser: true,
        }),
        commonjs(),
        replace({
            ENV: JSON.stringify(process.env.NODE_ENV || "development")
        }),
    ]
};   

1652356020(1).png

1652355939(1).png