likes
comments
collection
share

你的Typescript项目也是使用 rollup+api-extractor 打包的吗?

作者站长头像
站长
· 阅读数 48

最终打包效果

你的Typescript项目也是使用 rollup+api-extractor 打包的吗?

这里以web-loading插件为例。最初使用Webpack打包,因为其灵活性和多样化的生态,支持多种加载器和插件。但是,后来发现我的项目并没有涉及到复杂的加载器和插件功能,Webpack更适用于框架项目。因此,我转向了更为轻便的Rollup,并使用api-extractor来合并TS类型定义,使得打包后的插件文件更加紧凑、大小更小。

安装

npm i typescript rollup rollup-plugin-terser @microsoft/api-extractor -D

package.json重要配置

{
    "main": "./dist/web-loading.js", // 指定引入入口
    "typings": "./dist/web-loading.d.ts", // 指定TypeScript类型入口,提供给Typescript编译器使用
    "jsdelivr": "./dist/web-loading.js", // 指定了通过 jsdelivr CDN 加载的入口文件路径
    "unpkg": "./dist/web-loading.js", // 指定了通过 unpkg CDN 加载的入口文件路径
    "module": "./dist/web-loading.esm-bundler.js", // 指定ES Module引入入口
    "scripts": {
        // 首先tsc 打包,rollup抽离,api-extractor run 合并ts类型
        "build": "tsc && rollup -c rollup.config.js && api-extractor run",
    },
}

可以在打包完成之后根据自己的路径填充。

tsc配置文件

tsconfig.json

{
  "compilerOptions": {
    "target": "ES5",
    "module": "ESNext",
    "declaration": true,
    "outDir": "lib"
  },
  "include": [
    "./src/**/*"
  ]
}

这里根据自己业务指定,这里是最终将项目打包成ES模块项目,并最终输出到根目录的lib路径中。

tsc之后的效果

你的Typescript项目也是使用 rollup+api-extractor 打包的吗?

rollup配置文件

rollup.config.js

import { defineConfig } from 'rollup'
import { join } from 'path'

import { terser as rollupTerser } from 'rollup-plugin-terser'
import rollupJSON from '@rollup/plugin-json'
import rollupCommonJS from '@rollup/plugin-commonjs'
import rollupReplace from '@rollup/plugin-replace'
import rollupNodeResolve from '@rollup/plugin-node-resolve'

/**
 * @typedef {'umd' | 'cjs' | 'esm-bundler'} OutputFormat
 */

/**
 * @param {OutputFormat} format
 * @param {boolean} minify
 * @returns {string}
 */
function replaceProcessNodeEnv(format, minify) {
  switch (format) {
    case 'umd':
    case 'cjs':
      return minify ? '"production"' : '"development"'
    case 'esm-bundler':
      return 'process.env.NODE_ENV'
    default:
      throw new TypeError(`Unsupport format: ${format}`)
  }
}

/**
 * @param {OutputFormat} format
 * @param {boolean} minify
 * @returns {string}
 */
function replaceDev(format, minify) {
  switch (format) {
    case 'umd':
    case 'cjs':
      return minify ? 'false' : 'true'
    case 'esm-bundler':
      return 'process.env.NODE_ENV !== "production"'
    default:
      throw new TypeError(`Unsupport format: ${format}`)
  }
}

/**
 * @param {OutputFormat} format
 * @param {boolean} minify
 * @returns {import('rollup').RollupOptions}
 */
function createOption(format, minify) {
  // 需要指定输出文件前缀
  const name = `web-loading${format === 'umd' ? '' : `.${format}`}${minify ? '.min' : ''}.js`
  return {
    // 入口
    input: join(__dirname, 'lib/index.js'),
    plugins: [
      rollupNodeResolve({
        mainFields: ['browser', 'module', 'main']
      }),
      rollupJSON(),

      rollupReplace({
        preventAssignment: true,
        'process.env.NODE_ENV': replaceProcessNodeEnv(format, minify),
        __DEV__: replaceDev(format, minify),
        __VERSION__: JSON.stringify(require('./package.json').version)
      }),
      rollupCommonJS({
        transformMixedEsModules: true,
        extensions: ['.js', 'jsx', '.ts', '.tsx']
      }),
      {
        name: 'typescript-class-pure',
        transform(code) {
          return code.replace(//** @class */ (function/g, '/*#__PURE__*/ (function')
        }
      },
      ...(minify
        ? [
            rollupTerser({
              output: {
                comments: false
              },
              module: format === 'esm-bundler'
            })
          ]
        : [])
    ],
    output: {
      // 最终输出文件路径
      file: join(__dirname, 'dist', name),
      format: format === 'esm-bundler' ? 'esm' : format,
      name: 'rustOption',
      exports: 'named'
    }
  }
}

export default defineConfig([
  createOption('umd', false),
  createOption('umd', true),
  createOption('cjs', false),
  createOption('cjs', true),
  createOption('esm-bundler', false)
])

这里可以把它当作固定写法,也可以自定义,但createOption函数中输出可以自定义文件前缀。

rollup -c rollup.config.js 之后的效果

你的Typescript项目也是使用 rollup+api-extractor 打包的吗?

此时已经将lib中的js文件抽离,并打包了输出dist路径中。

api-extractor配置文件

api-extractor.json

{
  "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json",

  "mainEntryPointFilePath": "<projectFolder>/lib/index.d.ts",

  "bundledPackages": [],

  "compiler": {
    "tsconfigFilePath": "<projectFolder>/tsconfig.json"
  },

  "apiReport": {
    "enabled": false
  },

  "docModel": {
    "enabled": true
  },

  "dtsRollup": {
    "enabled": true,
      // 合并类型后的文件名
    "untrimmedFilePath": "<projectFolder>/dist/web-loading.d.ts"
  },

  "tsdocMetadata": {
    "enabled": true,
    "tsdocMetadataFilePath": "<projectFolder>/dist/tsdoc-metadata.json"
  },

  "messages": {
    "compilerMessageReporting": {
      "default": {
        "logLevel": "warning"
      }
    },

    "extractorMessageReporting": {
      "default": {
        "logLevel": "warning"
      },
      "ae-forgotten-export": {
        "logLevel": "none"
      }
    },

    "tsdocMessageReporting": {
      "default": {
        "logLevel": "warning"
      }
    }
  }
}

注意untrimmedFilePath最后输出的类型文件名。

api-extractor run之后的效果

你的Typescript项目也是使用 rollup+api-extractor 打包的吗?

可以看到项目中新增了合并后的类型文件,最后根据package.json配置入口即可。

npm上传配置

为了上传npm插件包时减小文件体积,可以新增一个名为.npmignore的配置文件,并在其中列出不需要被上传到npm注册表中的文件或目录。这样,在运行npm publish后,只会将定义在package.json中的files字段以及符合.npmignore设置的文件列表一并打包发布,自己的源码就不会被上传到npm仓库,从而使npm插件包的文件大小更小。

src
temp
lib
.eslint*
docs
api-extractor.json
rollup.config*
tsconfig*
package-lock.json
转载自:https://juejin.cn/post/7244192848063987773
评论
请登录