全网最全教程~
一、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打包
(附:webpack v4 常用配置教程:https://blog.csdn.net/u010059669/article/details/110040954)
下面是对于组件来说最常用的webpack配置说明,当前webpack版本为 v5.66.0。
1、入口配置:
entry: {
index: './src/index',
},
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: [
]
},
(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']
},
(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,超过该大小时就独立出来。
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属性配置排除列表。就是说让你插件项目里引用的第三方依赖不进行打包,只打包你自己的代码。比如我的插件里引用react 、react-dom 和react-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 目录创建指向你插件脚本的链接。
README.md 说明文档
五、发布
直接参考我之前写的发布教程吧:https://blog.csdn.net/u010059669/article/details/109715342
六、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')
},
],
}),
],
- 然后package.json里配置
"typings": "dist/index.d.ts" ,发布即可。
|