npm插件制作(全网最全教程~)

一、npm

npm是h5前端最常用的包管理工具,官方的npm仓库(传送门),用来存储第三方包(插件),通过npm命令下载安装和管理。

npm是随着node.js一起诞生的,起初是node.js用来管理包依赖的工具,后来随着webpack这类打包工具的兴起,npm逐渐成为h5前端使用和管理第三方插件的默认平台。

二、插件

制作插件,无论是功能代码还是业务代码,或者是组件库,发布后能在多个项目工程中复用,显著的提升团队效率。(私有代码请发布到公司私有仓库,过程和发布npm类似)。

相对于js功能类的插件来说,组件插件的配置更加复杂,下面以一个ts编写的react组件为例

插件地址:https://github.com/neohan666/react-router-waiter,里面有完整代码。)

组件的代码内容不作关注,只关注组件的从制作打包到发布到npm仓库的流程。

首先搭建一个基础的插件项目,完整项目如图:

  • src 是核心源码目录。
  • dist 是打包后的文件目录。

三、webpack打包

  • 打包的主要目的是为了处理代码的兼容性问题。

    例如,前端编写使用了es6语法,而es6语法在一些浏览器和webview环境里兼容性不好,需要babel工具降级。还有,组件的css样式也可能存在一定的兼容性问题,需要postcss工具处理。

  • 另外需要知道,平时使用的项目默认不会对npm_modules里的依赖包进行额外的打包处理,而是直接拿依赖包的源码使用。

    所以需要插件作者提前进行处理再对外发布。

(附:webpack v4 常用配置教程:https://blog.csdn.net/u010059669/article/details/110040954)

下面是对于组件来说最常用的webpack配置说明,当前webpack版本为 v5.66.0。

1、入口配置:

entry: {
  index: './src/index',
},
  • 插件的入口文件和平时使用的html项目不同,插件的入口文件只需要做一件事,即:导入,导出。
    import RouterWaiter from './RouterWaiter/index'
    
    export default RouterWaiter
    
  • 左侧的index属性是入口的bundle名,必要的时候可以配置多个入口。

2、出口配置

const path = require('path')

output: {
  filename: '[name].js',
  path: path.resolve(__dirname, './dist'),
  library: {
    type: 'commonjs-static',
  },
  clean: true,
},
  • filename,打包文件名,[name]指代入口的bundle名,这里就相当于index.js,插件打包不需要加各种hash。
  • path,打包目录。
  • library,用于配置插件使用时的引用模式。
    • type字段来配置具体使用哪种模块化加载方案,在webpack4及webpack5早起的版本中一般使用umd,打包后能自动适配 commonjs、esm (es6)、amd、umd等模式。官方文档:传送门。在webpack v5.66.0以上版本新增了commonjs-static,适配 commonjs 和 esm 这两种最常用的方式,这样打包后就能同时使用const a = require('a')import a from 'a'两种方式引用。
  • clean,配置在打包前是否清空原打包目录,在webpack4中是使用clean-webpack-plugin插件,webapck5里内置了。

3、extensions

resolve: {
  extensions: ['.tsx', '.ts', '.js'],
},
  • extensions 用于配置文件引入时的扩展名优先级。
  • 比如你在你的插件项目里通过import a from './index引入文件,但是没有写文件扩展名,就会按照这个优先级依次查找 index.tsx >>> index.ts >>> index.js。
  • 因为我项目是ts编写的,extensions有个默认值,不包含ts和tsx,所以需要手动配置。

4、loader

loader用于解析不同扩展名的文件做处理。

module: {
  rules: [
    // 在这里写各种loader
  ]
},
(1)babel-loader
{
  test: /\.(jsx?|tsx?)$/,
  exclude: /node_modules/,
  use: [
    {
      loader: 'babel-loader',
      options: {
        cacheDirectory: true,
      }
    }
  ]
},
  • babel-loader在webpack使用时会读取配置文件:babel.config.js,内容如下。
    module.exports = {
      presets: [
        '@babel/preset-env',
        '@babel/preset-react',
        '@babel/preset-typescript',
      ],
    }
    
    @babel/preset-env,用于根据目标浏览器环境(browserlist配置)自动适配降级。
    @babel/preset-react,主要用于处理react的jsx语法。
    @babel/preset-typescript,用于使用babel-loader处理ts,替代ts-loader的作用。
(2)postcss-loader
{
  test: /\.css$/,
  use: ['style-loader', 'css-loader', 'postcss-loader']
},
{
  test: /\.less$/,
  use: ['style-loader', 'css-loader', 'postcss-loader', 'less-loader']
},
  • postcss-loader在webpack使用时会读取配置文件:postcss.config.js,内容如下。
    module.exports = {
      plugins: {
        autoprefixer: {}
      }
    }
    
    autoprefixer 用于根据目标浏览器环境(browserlist配置)自动处理css兼容,例如自动添加浏览器内核前缀(-webkit-、-ms-)。
(3)图片资源
{
  test: /\.(jpe?g|png|gif|svg)$/i,
  type: 'asset',
  parser: {
    dataUrlCondition: {
      maxSize: 4 * 1024,
    },
  },
},
  • 在webpack4里是通过file-loader和url-loader来配置,而webpack5里内置了。
  • type字段配置类型,参考官方文档:传送门
  • 通过maxSize配置资源在小于4kb时转为base64格式嵌入js,超过该大小时就独立出来。
    • type: ‘asset/resource’

5、js压缩混淆

optimization 用于webpack打包性能方面的配置。

const TerserWebpackPlugin = require('terser-webpack-plugin')

optimization: {
  minimize: true,
  minimizer: [
    new TerserWebpackPlugin({
      terserOptions: {
        compress: {
          pure_funcs: ['console.log']
        }
      }
    }),
  ],
},
  • terser-webpack-plugin,用于js压缩混淆、自动删除注释等。
  • 以上配置了自动删除console.log语句,对于插件来说,不应该在代码出现log日志,否则会对别人项目的日志环境造成污染。

6、externals

externals用于配置插件项目中引用的外部依赖该如何处理。

const nodeExternals = require('webpack-node-externals')

externalsPresets: { node: true },
externals: [
  nodeExternals({
    allowlist: []
  })
],
  • webpack-node-externals,用于自动配置外部不打包模块,allowlist属性配置排除列表。就是说让你插件项目里引用的第三方依赖不进行打包,只打包你自己的代码。比如我的插件里引用reactreact-domreact-router-dom,这=三个本身就是使用我这个插件的项目一定会有的,项目在使用时会打包处理,不需要我再打包进我的插件里。
  • 如果哪个第三方依赖需要打包处理,可以用allowlist字段配置排除。

四、package.json

插件里的package.json,里面的字段配置与npm发布息息相关。

  • name npm包名
  • version npm包版本号,版本号是很有讲究的,一般用0.0.0形式分为三部分。第一部分用于不兼容更新,第二部分用于功能新增,第三部分用于bug修复。
  • description npm包的描述
  • main 引用npm包的入口文件
  • keywords npm官方仓库搜索时的关键词
  • license 开源协议类型,对应LICENSE文件。
  • files npm上传文件白名单,有些文件是默认会上传的,例如LICENSE、package.json、README.md。(.npmignore文件配置的是黑名单)
  • repository 源码仓库地址
  • homepage 插件官网,没有时默认取repository的地址
  • dependencies dependencies定义插件在生产环境所依赖的包,外部项目安装该插件时也会自动安装插件dependencies里的包(如果外部项目已安装过这些依赖就不再重复安装了),所以注意区分插件的dependencies和devDependencies
  • peerDependencies 插件本身可能依赖一些其他包(即上述dependencies定义的包),且对依赖包有版本要求,就可以用peerDependencies来指定这些依赖的版本范围,如果外部项目在安装当前插件前已经安装过这些依赖,但不符合版本范围,在安装当前插件时就会有警告提示。更多参考:传送门
  • typings ts类型声明文件的路径
  • bin 用于配置命令脚本,我这里组件插件用不到,如果你的插件是node命令,就用这个配置命令名及对应的可执行脚本文件路径。npm在安装插件时会自动在node_modules/.bin目录创建指向你插件脚本的链接。
  • sideEffects 用于tree shaking优化,默认为true,设置为false或一个数组(排除列表)可以让插件支持tree shaking,不清楚的请慎用。更多参考:传送门

README.md 说明文档

五、发布

直接参考我之前写的发布教程吧:传送门
在这里插入图片描述

六、TS的支持

如果你的插件想要在ts项目中引用时支持类型检查,就需要额外做些配置。

上面package.json提到了typings字段的作用,就是指向ts类型声明文件。所以你需要额外编写个以.d.ts为后缀的文件。

interface RouterWaiterType {
  (payload: any): JSX.Element;
}

declare const RouterWaiter: RouterWaiterType

export default RouterWaiter
  • 上述是我这个react组件的声明文件示例内容。我的组件是默认导出的,所以这里保持一致,先通过declare声明变量及类型,然后export default默认导出。(如果你的插件是按需导出的就改成按需导出)
  • 一般一个插件可能用到的类型有很多,比如我的组件属性类型、属性值的类型等等,最好都手动导出出来供外界引用,通过export type {}导出,使用时import {} from ''即可。

如果你的插件本身也是用ts编写的,那这个类型声明文件可能需要复用,你插件开发的时候需要用,还需要导出给外界用,然而开发用的文件不能以.d.ts为后缀。

这种情况可以考虑只维护一个开发使用的,然后通过webpack打包时利用copy-webpack-plugin来复制一个到打包目录作为外界使用。

const CopyPlugin = require('copy-webpack-plugin')

plugins: [
 new CopyPlugin({
    patterns: [
      {
        from: path.resolve(__dirname, './src/types.ts'), // 插件开发使用的,
        to: path.resolve(__dirname, './dist/index.d.ts') // 供外部ts项目使用的
      },
    ],
  }),
],
  • 然后package.json里配置"typings": "dist/index.d.ts",发布即可。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值