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

最终打包效果

321.png

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

安装

npm i typescript rollup rollup-plugin-terser @microsoft/api-extractor -D
npm i typescript rollup rollup-plugin-terser @microsoft/api-extractor -D
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",
},
}
{

    "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",
    },
}
{    "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/**/*"
]
}
{

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

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

tsc之后的效果

22.png

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)
])
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)
])
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 之后的效果

222.png

此时已经将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"
}
}
}
}
{
  "$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"
      }
    }
  }
}
​
{  "$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之后的效果

333.png

可以看到项目中新增了合并后的类型文件,最后根据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
src
temp
lib
.eslint*
docs
api-extractor.json
rollup.config*
tsconfig*
package-lock.json
src temp lib .eslint* docs api-extractor.json rollup.config* tsconfig* package-lock.json

© 版权声明
THE END
喜欢就支持一下吧
点赞0

Warning: mysqli_query(): (HY000/3): Error writing file '/tmp/MYTkOc0h' (Errcode: 28 - No space left on device) in /www/wwwroot/583.cn/wp-includes/class-wpdb.php on line 2345
admin的头像-五八三
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

图形验证码
取消
昵称代码图片