背景
前段时间写过一篇 一文拿下Web端基于AudioWorkletNode录制音频 , 然后现在毕设什么的都搞定了比较闲, 就来琢磨怎么将其发包(主要是想重操一下发包流程),此篇整理详细记录实现过程, 以防自己以后多走弯路
搞定npm
要发布一个npm包首先你要有对应的npm账号, 这里就不赘述了
在操作之前, 先通过npm get registry确认是否为官方源
- 若显示为:
https://registry.npmjs.org/则为官方源 - 若显示为:
https://registry.npmmirror.com或者https://registry.npm.taobao.org(过期了的)则为淘宝源, 此时如果你登录的话其实是登录cnpm, 故需要可通过npm config set registry https://registry.npmjs.org进行切换
接着呢, 在命令行输入npm login 或者npm adduser进行登录,显示如下或者让你输入账密登录,跟着流程走就好
想确认是否登录成功可以通过npm whoami, 如已经登录了的话则会显示你的账号名称
关键步骤
建包
新建一个文件夹并使用npm init,会让你输入一些关键属性接着生成package.json,以下为发包可能涉及到的一些属性
name: 该包的名称description: 该包的简述main: 该包的入口文件scripts: 定义一组可以运行的node脚本author:作者名contributors: 贡献者keywords: 一组关键词, 影响搜索repository: 指定仓库链接private: 如果设置为true,则可以防止应用程序/软件包被意外地发布到npm。 故这里要么不指定要么设置为falsefiles: 可以通过files指定需要跟随一起发布的内容来控制npm包的大小,避免安装时间太长
当然这里如果想更详细地了解package.json的属性, 指路: package.json 配置完全解读 - 掘金 (juejin.cn)
发布
当业务内容都搞完了就可以发布了, 在发布之前需要先检查一下包名称是否有问题, npm是不允许有同名的包, 当你发包时,若已有同名的包那么就会失败
可以先通过npm search搜索是否已有同名包, 若有符合的包名称则会显示相关信息, 匹配上的包名称还会标红。 如果此时发现有同名的包, 那么就修改package.json中的name以修改包名称。注意包名称不能出现下划线、大写字母、空格等字符,可以有连字符和中划线。

发布的话则使用npm publish就OK了。 在发包的时候会显示该包内包含了什么文件,以及相关的包的信息。 一般来说除了package.json中通过files指定的目录之外, 还会带上整体的README文件和package.json文件
当然发包偶尔就会失败(超时).... 多试几次就好了

更新
当包内容有更新时, 直接使用npm publish是会失败的,因为此时的版本号与现有的版本号重复了。
故需要先更新版本号, 有两个方法可以修改版本号:
- 直接修改
package.json的version属性 - 通过命令行
npm version [option]更新版本号, 主要option如下major: 主版本号 -- 大更新 1.0.0 -> 2.0.0minor: 次版本号 -- 小更新 1.0.0 -> 1.1.0patch: 补丁版本号 -- 打补丁 1.0.0 -> 1.0.1premajor: 预备主版本preminor: 预备次版本prepatch: 预备补丁版本
当然还有包的撤销和弃用, 这按需搜索就好了
结合内容
这个包的内容很简单, 基本源代码就是之前文章内写的。记录也不是为了记录源码内容, 而是其他步骤。
src目录下即为核心代码, index.ts文件作为入口文件。
.d.ts声明文件
发布一个包最好要生成对应的 .d.ts 文件,提供代码补全和接口提示的功能, 没提供的话一般IDE会有报错提醒。
在该项目中我们是通过@babel/preset-typescript去处理TS文件的, 但是@babel/preset-typescript在处理typescript的时候是没有提供生成声明文件这个功能的, 故可以通过tsc --emitDeclarationOnly去生成声明文件。
或者使用ts-loader去处理, 这个就直接提供声明文件
搞定声明文件后, 需要在package.json的types字段去指定声明文件: "types": "dist/main.d.ts",
webpack配置
源码使用webpack作为打包工具,内部主要提供三条命令, 根据不同的命令使用不同的webpack配置文件
demo: 构建生成demo, 可以通过HTML文件直接体验效果dev:开发中用于调试功能, 使用webpack-dev-serverbuild: 构建生成发包产物
使用webpack需要先进行安装npm install --save-dev webpack webpack-cli
对于build构建而言, 命令行为: webpack --mode=production, 默认的配置文件为webpack.config.js
js
const { join } = require('path');
const CopyPlugin = require('copy-webpack-plugin');
module.exports = {
entry: join(__dirname, './src/index.ts'), // 打包入口
output: {
filename: '[name].js', // 产物名称
// 产物目录
// 这里都收归到dist目录下, 最后发包的package.json指定files为dist即可
path: join(__dirname, './dist'),
// 每次构建齐纳都先清空dist目录
clean: true,
publicPath: '/',
// 暴露从入口导出的内容, 如果你构建之后发现产物基本没东西那么就是忘记配置这个了
library: {
name: '"webAudioRecorder', // 构建产物的名称, 这里需要与入口数量匹配
type: 'umd' // 构建产物支持的方式,
},
},
resolve: {
// webpackh会尝试按顺序解析这些后缀名, 列入使用到的文件后缀即可
extensions: ['.ts','.js']
},
plugins: [
// 业务内容中涉及到process.js文件是通过addModule的方法
// 放在Web Audio rending thread中运行
// 在构建中webpack是识别不到他的, 故需要将它复制到产物中, 这里使用CopyPlugin
//类型文件同理
new CopyPlugin({
patterns: [{
from: './src/recorder/processor.js',
to: './processor.js'
}, {
from: './index.d.ts',
to: './main.d.ts',
}]
})
],
optimization: {
minimize: false // 是否压缩,这里看个人需求就好了
},
// 这里就使用babel处理, 没啥了
module: {
rules: [
{
test: /.(ts)$/,
use: {
loader: 'babel-loader',
options: {
presets: [
'@babel/preset-env',
'@babel/preset-typescript'
]
}
},
}
],
},
}
output.library.type支持的类型指步:output.library.type
对于dev和demo而言, 录音功能其实通过一些按钮调用就好了, 故先在example目录下生成对应的HTML的模板以及对应的调用文件。 如果是开发中, 调用文件则使用src目录下的代码。 如果是生成demo的话, 则调用dist目录下的构建产物(如果发版了也可以使用包产物)。 
dev的命令行则使用webpack-dev-server去启动dev": "webpack-dev-server --mode=development --config webpack.dev.js"
demo的命令行则使用webpack去启动"demo": "webpack --mode=production -c webpack.dev.js"。
两者的配置文件都为webpack.dev.js
js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CopyPlugin = require('copy-webpack-plugin');
module.exports = {
// 入口
entry: path.join(__dirname, './example/index.js'), // 调用文件作为入口
devtool: 'source-map',
devServer: {
port: 3000, // 服务端口号
hot: true, // 开启热更新
host: 'localhost', // 在本项目中,相关API需要在安全上下文调用, 故需要指定host
historyApiFallback: true, // 解决history路由404问题
},
output: {
filename: 'index.js',
clean: true,
path: path.join(__dirname, './demo') // 构建产物放在demo
},
module: { ... }, // 省略
resolve: { ... }, // 省略
plugins: [
// 使用模板HTML , 生成产物
new HtmlWebpackPlugin({
template: path.resolve(__dirname, './example/index.html'),
filename: 'index.html',
inject: true
}),
// 将静态资源copy过去
new CopyPlugin({
patterns: [{
from: './src/recorder/processor.js',
to: './processor.js'
}]
})
]
};
当然如何要应用在其他项目中进行测试, 还可以用npm link相关功能。 比如在开发业务专属eslint规则包的时候, 直接npm link过去业务项目中测试会高效很多