手把手教你设计npm包-系列二(构建工具搭建)

284 阅读3分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。
——Bug修复员-鲁宽宽

前言


 阅读过上篇(手把手教你设计npm包-系列一 )的伙伴应该可以想到此篇主要内容是什么,那就是如何使用Rollup来构建源码。

 此篇会详细(有点长)介绍每一步的配置及相关依赖,若只想看整体效果,可以访问源码地址

 实现能力主要有:

  • 输出多端运行源码
  • 支持ts
  • 支持按需加载

构建工具配置


初始化项目

npm init

// 项目目录
|- src
  |- index.js
|- package.json

// package
{
  "name": "test",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC"
}
// index.js
const test = () => {
    return true
}
export default test
安装rollup

npm install rollup -D

// 项目目录
|- build
  |- rollup
    |-rollup.config.prod.js
|- src
  |- index.js
|- package.json

// pageage 修改
{
    "scripts": {
        "build": "rollup -c build/rollup/rollup.config.prod.js",
    }
}

 配置rollup,支持导出esmumdcjs类型。

export default {
  input: 'src/index.js',
  output: [
    {
      file: `lib/index.esm.js`,
      format: 'esm'
    },
    {
      file: `lib/index.umd.js`,
      format: 'umd',
      name: 'JSUTILS'
    },
    {
      file: 'lib/index.cjs.js',
      format: 'cjs'
    }
  ],
  external: ['fs']
}

 初次尝试npm run build,提示构建成功,还挺简单。不过检查构建后代码,会发现ES6的属性没有被转换为ES5,接下来就使用babel重新构建下。

安装babel

npm install @babel/core @babel/preset-env -D
npm install core-js

 运行会报错,提示需要安装rollup的babel插件。安装rollup插件:

npm install @rollup/plugin-babel -D

 此时的配置如下:

// 项目目录
|- build
  |- rollup
    |-rollup.config.prod.js // 修改
|- src
  |- index.js
|- package.json
|- .babelrc // 修改

// .babelrc
{
  "presets": [
    [
      "@babel/preset-env",
      {
        "modules": false,
        "useBuiltIns": "usage",
        "corejs": "3.8"
      }
    ]
  ]
}

// rollup.config.prod.js
import { babel } from '@rollup/plugin-babel'
export default {
  input: 'src/index.js',
  output: [...],
  external: ['fs'],
  plugins: [
    babel(
      {
        babelHelpers: 'bundled',
        extensions: ['.js', '.ts'],
        exclude: 'node_modules/**'
      }
    )
  ]
}

  再次运行发现是ok的,不过我们尝试使用Promise功能,发现构建后的文件含有以下代码:

// index.esm.js
import 'core-js/modules/es.object.to-string.js';
import 'core-js/modules/es.promise.js';

  造成这个原因是因为rollup本身不会对依赖包进行额外的解析,但若要输出一个独立的包,是需要解决这个问题的,很简单,只需要添加rollup相应插件就可以了。

配置rollup插件

npm install @rollup/plugin-node-resolve @rollup/plugin-commonjs -D

  这两个包可以对node_modules依赖及commonjs语法进行解析。详细配置:

// rollup.config.prod.js
import { nodeResolve } from '@rollup/plugin-node-resolve' 
import commonjs from '@rollup/plugin-commonjs'
export default {
  input: 'src/index.js',
  output: [...],
  external: ['fs'],
  plugins: [
    babel(...),
    nodeResolve({
      preferBuiltins: false
    }),
    commonjs(
      {
        sourceMap: false
      }
    )
  ]
}

  配置完成并运行后,查看源码发现多了许多并不熟悉的代码,这些就是支持新属性(promise)的代码。

  到了这里基本已经结束,下面再讲讲如何配置ts

配置Ts

npm install typescript rollup-plugin-typescript2 @babel/preset-typescript -D

  修改相关配置

// 项目目录
|- build
  |- rollup
    |-rollup.config.prod.js // 修改
|- src
  |- index.js
|- package.json
|- .babelrc // 修改
|- tsconfig.json // 新增

// tsconfig.json
{
  "compilerOptions": {
    "baseUrl": ".",
    "isolatedModules": true,
    "target": "esnext",
    "useDefineForClassFields": true,
    "module": "esnext",
    "moduleResolution": "node",
    "strict": false,
    "jsx": "preserve",
    "sourceMap": true,
    "resolveJsonModule": true,
    "esModuleInterop": true,
    "lib": ["esnext", "dom"],
    "removeComments": true,
    "declaration": true, 
    "noImplicitAny": false, 
  },
  "include": ["src/**/*.ts", "src/**/*.d.ts", "lib/**/*.ts", "lib/**/*.d.ts"],
  "references": []
}

// .babelrc
{
  "presets": [
    [
      "@babel/preset-env",
      {
        "modules": false,
        "useBuiltIns": "usage",
        "corejs": "3.8"
      }
    ],
    "@babel/preset-typescript" // 新增
  ]
}

// rollup.config.prod.js
...
import typescript from 'rollup-plugin-typescript2'
const getPath = _path => path.resolve(__dirname, _path)

export default {
  input: 'src/index.js',
  output: [...],
  external: ['fs'],
  plugins: [
    ...,
    typescript({
      tsconfig: getPath('../../tsconfig.json'), // 导入本地ts配置
      extensions: ['.js', '.ts']
    }),
  ]
}

  配置完成后,可以支持Ts的编写,并在构建时,输出相应的ts声明文件。这样在使用此包方法时可以给出友好提示(记得改package)。如下:

{
  "main": "lib/index.cjs.js",
  "module": "lib/index.esm.js",
  "typings": "lib/index.d.ts", // 配置相应的输出路径
}

结语


  详细代码参考:源码地址

  这份配置建议作为学习的参考或者内部使用。因为它不是最优的实现,比如并未接入eslint、单元测试等,故不适合一些复杂(开源、严谨)的项目。

  若是大家有较优的方案,也可以将地址留在评论区,让我们一同学习参考~

获取知识、沉淀总结、分享经验,很美妙的过程。

系列地址


手把手教你设计npm包-系列一(整体思路)