rollup规范化构建npm包的开发环境(亲测可用)

前言

之前写过一个测网速的小工具和一个Dom2Img的工具库,最终通过npm发布。由于这两个工具开发成本低,代码量比较小,也就没有进行工程化,没有打包过程,没有代码风格检测,更没有代码压缩.... 用tsc编译下就完事了。正好笔者将要开发一个实现思维导图的类库,于时便搭建了一个相对完善的js库的开发环境(TS+Rollup+ESLint)。

代码打包工具

  • webpack 是一个现代 JavaScript 应用程序的静态模块打包器(module bundler)。当 webpack 处理应用程序时,它会递归地构建一个依赖关系图(dependency graph),其中包含应用程序需要的每个模块,然后将所有这些模块打包成一个或多个 bundle。(webpack存在大量引导代码和模块函数)
  • rollup仅仅是一个代码打包器,将一个个小的代码块整合为一个大块且复杂的代码

如果使用场景中包含css、js、html和静态资源,那么使用webpack打包会更好;如果只是对js代码模块进行打包,可以使用rollup。

总之,rollup更加适合用来打包js库,而webpack适合用于构建前端应用程序

笔者选用rollup作为代码打包工具,相较于webpack它更加轻量化,且支持ES Module标准,充分利用esmd的优势构建出性能更优的类库。

bash 复制代码
# 项目初始化
mkdir lib-demo
cd lib-demo
npm init
pnpm i -D rollup 

配置Rollup

创建rollup配置文件rollup.config.js,这里贴出我的配置文件,由于rollup除了打包代码块外没有任何功能,所以需要一些插件来做其他的操作,我的配置文件中需要安装以下插件,插件看起来很多,但每个都有重要的作用!

shell 复制代码
pnpm i -D @rollup/plugin-babel @rollup/plugin-typescript @rollup/plugin-node-resolve @rollup/plugin-commonjs @rollup/plugin-json @rollup/plugin-terser
javascript 复制代码
// rollup.config.js

// 导出defineConfig方法可以让编辑器(VSCode)智能提示所有的rollup的配置项,很方便
import { defineConfig } from "rollup";
// 这里是babel的插件,用来处理es的转换,当然会用一个.babelrc配置文件,下面也会简单列出来
import { babel } from "@rollup/plugin-babel";
// rollup转译typescript的插件
import typescript from "@rollup/plugin-typescript";
// 使得rollup能够加载node_modules里的第三方模块
import { nodeResolve } from "@rollup/plugin-node-resolve";
// rollup编译源码中默认是esm,所以rollup无法识别CommonJS模块。比如某个依赖包里用到了cjs标准的导入语句,这个插件将他们转为esm的导入语句
import commonjs from "@rollup/plugin-commonjs";
// 为了使rollup能够导入json中的数据,需要这个插件
import json from "@rollup/plugin-json";
// 压缩代码插件
import terser from "@rollup/plugin-terser";
// 引入package.json
import pkg from "./package.json" assert { type: "json" };

// 拿到package.json的name属性来动态设置打包名称
const libName = pkg.name;
export default defineConfig({
  input: "index.ts",
  output: [
    {
      file: `dist/${libName}.cjs.js`,
      // commonjs格式
      format: "cjs",
    },
    {
      file: `dist/${libName}.es.js`,
      // es module
      format: "es",
    },
    {
      file: `dist/${libName}.umd.js`,
      // 通用格式可以用于node和browser等多个场景
      format: "umd",
      // 配合external使用,指出第三方库在具名导入时的名称
      // globals: {
      //   lodash: "_",
      // },
      // 注意如果是umd格式的bundle的话name属性是必须的,这时可以在script标签引入后window下会挂载该属性的变量来使用你的类库方法
      name: libName,
    },
    {
      file: `dist/${libName}.min.js`,
      format: "iife",
      name: libName,
      extend: true,
      plugins: [terser()],
    },
  ],
  plugins: [
    babel({ babelHelpers: "bundled" }), // 默认参数也是这个,这里显式调用是为了消除命令行窗口提示文字
    typescript(),
    nodeResolve(),
    commonjs(),
    json(),
  ],
  // 保持某些库的外部引用状态,将第三方库通过导入语句进行导入,而不是直接将其代码打包进模块中
  // external: ["lodash"],
});

这里有一点需要注意:rollup.config文件的扩展名可以是.js.mjs.cjs

  • 扩展名为.js时,rollup.config会被node当作 esm还是cmj模块取决与package.json中的type字段(默认为"commonjs"),type值为"module".js文件解释为es模块,反之亦然。
  • 扩展名为.mjs时,无论package.jsontype字段为什么值都将按照es模块语法进行处理
  • 扩展名为.cjs时,无论package.jsontype字段为什么值都将按照commonjs模块语法进行处理

所以当文件中使用了import/export时,一旦被当作commonjs标准解释就会报错了。

支持TypeScript

rollup中存在与ts相集成的插件@rollup/plugin-typescript,可以将ts代码转译为js代码。不过需要注意该插件依赖于typescripttslib这两这个包才能正常工作

shell 复制代码
pnpm i -D typescript tslib
# 初始化tsconfig.json
tsc --init
json 复制代码
{
  "compilerOptions": {
    "target": "es2016",                                  /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
    "module": "ESNext",                                /* Specify what module code is generated. */
    "moduleResolution": "node10",                     /* Specify how TypeScript looks up a file from a given module specifier. */
    "declaration": true,                              /* Generate .d.ts files from TypeScript and JavaScript files in your project. */
    "declarationDir": "dist/type",                           /* Specify the output directory for generated declaration files. */
    "esModuleInterop": true,                             /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */                      /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */
    "forceConsistentCasingInFileNames": true,            /* Ensure that casing is correct in imports. */
    "strict": true,                                      /* Enable all strict type-checking options. */            
    "skipLibCheck": true                                 /* Skip type checking all .d.ts files. */
  },
  "include": [
    "src/**/*.ts",
    "index.ts",
    ".eslintrc.cjs" // 重点,缺少它.eslintrc.cjs会报错
  ]
}

Babel配置

在根目录创建babel配置文件.babelrc

json 复制代码
// .babelrc
// 这里就不过多解释了,主要是modules:false这个配置项配置成false
// 否则 Babel 会在 Rollup 有机会做处理之前,将我们的模块转成 CommonJS ,导致 Rollup 的一些处理失败。
{
  "presets": [
    [
      "@babel/preset-env",
      {
        "useBuiltIns": "entry",
        "corejs": "3.6.4",
        "modules": false
      },
      "@babel/preset-typescript"
    ]
  ],
  "exclude": "node_modules/**"
}

创建打包命令

package.json中的"script"中添加"build"命令:rimraf -rf dist && rollup --config

然后执行 npm run build即可进行打包。

ts 复制代码
// 测试代码
// pnpm i -D lodash @types/lodash
import concat from 'lodash/concat'

console.log(concat([1, 2], 3, [4, 5]))
class Human {
  height: string
  weight: string
  constructor() {
    this.height = ''
    this.weight = ''
  }
}
class Student extends Human {
  private _study: number
  _sleep: number
  constructor() {
    super()
    this._study = 0
    this._sleep = 0
  }

  set study(val: number) {
    this._study = val
  }

  get study(): number {
    return this._study
  }

  setSleep(val: number): undefined {
    this._sleep = val
  }

  setHeight(val: string): void {
    this.height = val
  }
}

const stu = new Student()
stu.study = 10
stu.setHeight('178')
stu.setSleep(6)

打包输出为四个文件,分别对应commonjs、esm、umd以及压缩后的代码

配置ESLint

其实也有rollup和eslint集成的插件,但是我配置一直出错,索性直接用eslint好了

shell 复制代码
pnpm i -D eslint

# 初始化配置.eslintrc.js文件
npm init @eslint/config

eslint配置文件初始化的引导过程:

这样就生成了一份基础的eslint配置文件,基本可以满足平常所需的代码风格约束规则。

js 复制代码
// .eslintrc.cjs
module.exports = {
  env: {
    browser: true,
    es2021: true,
    node: true
  },
  extends: [
    'standard-with-typescript',
    'eslint:recommended',
    'plugin:@typescript-eslint/recommended'
  ],
  overrides: [
    {
      env: {
        node: true
      },
      files: ['.eslintrc.{js,cjs}'],
      parserOptions: {
        sourceType: 'script'
      }
    }
  ],
  plugins: ['@typescript-eslint'],
  parser: '@typescript-eslint/parser',
  parserOptions: {
    ecmaVersion: 'latest',
    sourceType: 'module'
  },
  rules: {}
}

要想及时的修复检测代码,在跟目录创建文件夹.vscode,在该文件夹下创建settings.json,内容为:

json 复制代码
{
  "prettier.enable": false,
  "editor.formatOnSave": false,
  "editor.codeActionsOnSave": {
    "source.fixAll": true
},
}

这样每次保存代码都会对出错代码进行自动修复。

最后再配置下eslint的忽略文件.eslintignore

bash 复制代码
*.sh
node_modules
*.md
*.woff
*.ttf
.vscode
.idea
dist
/public
/docs
.husky
.local
/bin
Dockerfile
相关推荐
胖蔡1 个月前
使用Rollup.js快速开始构建一个前端项目
前端·rollup.js
yanessa_yu4 个月前
配置@rollup/plugi-commonjs插件处理混合模块
前端·rollup.js
牛奶4 个月前
使用rollup搭建工具库并上传npm
前端框架·npm·rollup.js
sunny_6 个月前
🔥 爆肝5w字,带你深入前端构建工具 Rollup 高阶使用、API、插件机制和开发
前端·架构·rollup.js
尖椒土豆sss7 个月前
rollup+ts开发npm包的知识点总结
typescript·npm·rollup.js
尖椒土豆sss7 个月前
解决ts+rollup打包报错以及警告
typescript·rollup.js
CRPER7 个月前
一个typescript 5 + rollup 4 打包lib模板仓库实现
typescript·node.js·rollup.js
尖椒土豆sss7 个月前
用ts重构基于rollup的npm包踩坑记录
前端·typescript·rollup.js
喵喵捉鼠7 个月前
rollup打包的简单配置
javascript·rollup.js