webpack打包公共类库怎么做?

8,228 阅读15分钟

周五了,何不给自己加个餐呢,想着第二天不用上班了,就感觉要起飞有木有,所以写篇文章再下班吧。

知识点:

  • 一个关于前端日志打印的库。 npm地址
  • 本文(详细)介绍了一个规范的npm包应该如何发布
  • 如何用webpack打包公共类库,兼容不同环境,不同场景。

日常的日志调试是个很基础的东西,console.log也是我们每天都经常使用的东西,有一天看到朋友的项目日志是这样的。

于是我不禁产生了 ???

这要找自己的一个log日志得看花了眼,别人的log又不好随便删,于是日常开发经常是这样的**console.log(info,'=========')。

于是便想把console.log这个方法进行封装下,让调试起来更加方便,所以便准备发布一个npm包以便于以后也能使用。

所以,顺便为大家来详细介绍一个npm包该如何操作发布。

如何发布一个npm的包


先来了解下npm

众所周知,目前的前端现状是这样的:

当前前端开发离不开node_modules,前端工程化催生出了这个产物,让前端进而飞速发展,但是也就出现了一个项目有时候特别庞大的node_modules的情况发生,如果是windows,有时候甚至删除一个node_modules的文件夹都需要话特别长的时间,由此可见,这个东西的庞大,当然,言归正传,要知道我们在开发过程中的每一个包都是储存在npm的网站中的,在这里,你可以搜索到在你开发过程中所有用到的包,所以,当你有时候遇到下载的某某依赖有问题的时候,不妨来这里看看作者的说明文档。我们要想发布一个包,自然是先在这个网站注册一个账号,这里就跳过了。

初始化一个项目

我给自己起的包名叫sn-console,这个大家自己喜欢就好,我这样起的原因是因为本人英文名(SNine)。所以第一步npm init,然后这里一路回车,具体的配置我们在pakeage.json再去看看呗。

{
  "name": "log",   //你要发布的包名称
  "version": "1.0.0",//你要发布的版本号
  "description": "", //关于你这个包的一个简单描述
  "main": "index.js", //您的项目入口文件
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",		//作者名字
  "license": "ISC" //代码的许可证,是否允许开源商用什么某某之类的协议。
}

初始化完的项目就是这样一个基础页面,我们逐一将它完善:

1:前期准备

首先在目录创建index.js文件,这是package.json里面main.js指定的入口,这是代码入口。这个十分重要,特别是对于组件库。当你想在node_modules中修改你使用的某个组件库的代码时,首先在node_modules中找到这个组件库,第一眼就是要看这个main,找到组件库的入口文件,这个文件就是项目的入口文件,同时创建一个src文件夹,用于我们要写的代码存放,那么我们接下来的代码就写在src当中了。

在这里就以一个简单的案例来为大家详细介绍如何打包一个规范的npmjs公共库。

我们知道一般一个公共库不论你是一个ui库或是一个功能库,你的目的都是为了别人来使用,所以我们要满足这一些基本要求:

  • 要区分开发环境和生产环境
  • 要符合不同规范
  • 要让用户可以选择自己喜欢的方法使用

所以可以看出我们就需要用到webpack了,当然第一件事是下载webpack,由于webpack更新到5了,很多新的特性还不是特别清楚,所以我这里就直接下载4的版本了。

npm i webpack@4.44.0 webpack-cli@3.3.12 -D
  1. 下载好这个之后呢,同时在根目录创建webpack.config.js 用过webpakc的朋友都知道这是webpack的配置文件,就先不解释了。
  2. 同时去pakeage.json里面创建一条script命令用于打包
{
  "name": "sn-console",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "webpack" //新建一条命令 npm run build 打包库
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "webpack": "^4.44.0",
    "webpack-cli": "^3.3.12"
  }
}

2:封装log库

基础工作做完了,这里呢就是封装了,为了给大家讲的更加详细,这里再为大家扩展一些知识:

我们先来配置一个webpake的基本配置,

module.exports = {
    entry: './src/index.js',
    output: {}
}

这里不配置什么东西,看看webpakc默认会打包成什么样吧。

为了让大家更很理解,我们只写一个简单的方法让大家更好理解,我们在src/index里面写一个方法,也很简单:

export default function add(a, b){
    return a + b;
}

我们写一个加法函数导出,然后我们执行npm run build保存打包看看,我们会发现产生了一个dist目录,打包出来的文件叫main.js,且是压缩过得文件,这显然不符合我们的预期,首先我们希望可以打包两个文件,一个是开发环境使用,一个是生产环境使用,那么如何来解决这个问题呢,当然是通过配置webpakc了。

module.exports = {
    entry: {
        "addNumber": './src/index.js',
        "addNumber.min": './src/index.js',
    },
    output: {
        filename: "[name].js",
        library: "addNumber",
        libraryTarget: "umd",
    }
}

我们只需要这样配置,就可以在dist分别,打包addNumberaddNumber.min两个文件了,那么,我们的问题解决了么?打开两个文件之后我们发现,两个文件都是压缩过的,这明显不符合我们预期,虽然有了两个文件,但是我们希望有一个未压缩的在开发环境使用,所以我们需要继续配置,我们知道,在webpake配置中mode参数是用来配置环境的,但是只能指定一个环境,所以我们对其直接禁用,并引入一个压缩的插件来解决这个问题,同样插件我们也下载4.x版本。

npm install terser-webpack-plugin@4.2.0 -D

然后再来看看webpack配置

const TerserPlugin = require('terser-webpack-plugin');
module.exports = {
    entry: {
        "addNumber": './src/index.js',   //为了输出两个文件,我们指定两个出口
        "addNumber.min": './src/index.js',
    },
    output: {
        filename: "[name].js",  //因为是多个文件,所以这样写
        library: "addNumber",  //打包出去库的名字
        libraryTarget: "umd",   //定义的规范,打包库的目标选项,包含var 、 assign 、 this 、 window 、 global 、 commonjs 、 commonjs2 、 commonjsmodule 、 amd 、 umd 、 umd2 、 jsonp这么多 umd是最通用的规范 默认值是var
    },
    mode: "none", //因为自带的只能指定一种环境,所以我们直接关闭,利用插件实现
    optimization: { //这个字段很强大,我们做webpack的代码分割,摇数,tree shake等都会用到这个字段
        minimize: true, //开启插件
        minimizer: [new TerserPlugin({
            test: /\.min.js/  //提供一个正则,表示符合有min.js的就进行压缩
        })]
    }
}

这样一来,就可以实现真正的打包了,他实现了,

  1. 打包出来两个环境,开发和生产压缩和未压缩的功能,
  2. 采用umd规范打包,使用的时候,是包含了多个标准的,不论是esmodel 还是commonJs等各种环境都可以正常使用,所以这也是我们打包公共库推荐的一种方式。这样不论你是import 还是require都可以拿到了,是不是很方便呢?

3:测试我们的库

一般来说,如果要测试正式的库,当然要写测试用例比较好,但是今天给大家的案例非常简单,写个html引入好了,我们在目录创建一个index.html并引入打包的文件,来测试下,我们在webpack配置的时候像外暴露了一个library是addNumber,我们直接打印他:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script src="./dist/sn-console.js"></script>
    <script>
        console.log(addNumber)
    </script>
</body>
</html>

我们引入并打印了看看结果:大家猜是什么呢?

打开控制台一看?

我们发现,居然是一个module,这你让我怎么用,打开一看,哦?原来我们的方法在下面的default里面,这不是加找到了嘛,我们打印一个这个add是不是我们的方法:console.log(addNumber.default(99,1))打开控制台一看,果然是100,这个方法实现了,但是总不能让我们每次都加上default来调用吧,太麻烦了吧,和我想的不一样呢,怎么办呢?怎么解决呢?当然还是靠webpack来实现洛,在webpack的配置还有一项重要的配置,libraryExport:"default",在output中添加上这个配置,表示导出的是默认值,如果不指定,我们导出的是一个module,加上这个配置,导出的就是default,就可以直接使用啦,至此,我们的打包环境到此结束了。

接下来需要干嘛呢?

4:环境区分,开发/生产

这时候我们发现,打包的文件在dist下,而我们package.json的入口问就是index.js,那么我们需要怎么做呢,当然非常简单啦。在index通过环境区分分别引入dist下面的压缩和未压缩文件就好啦。

"use strict"
if(process.env.NODE_ENV === 'production'){
    module.exports = require('./dist/sn-log.min')
}else{
    module.exports = require('./dist/sn-log')
}

这样就好啦,我们的一个规范的npm包就完成了,可以在不同环境,不同方式引入,还区分了两种环境。

5:补充package.json

写好了这样一个包就准备发布了,在发布前,我们回到最开始,我们先补齐package.json的内容吧,因为他的参数其实很多的。

{
  "name": "sn-console", //发布的包名称
  "version": "1.0.0", //发布的包版本号
  "description": "Beautiful and effective console printing about JS", //一句简短的描述介绍包
  "main": "index.js",	//指定项目入口文件
  "scripts": { //script脚本
    "test": "echo \"Error: no test specified\" && exit 1",
    "dev": "webpack"
  },
  "keywords": [ //关键词,在npm网站输入这些关键词就可以搜索到你的包
    "console",
    "snine",
    "log"
  ],
  "author": "Snine", //这个包的作者,可以写自己名字就好
  "license": "ISC",  //当前包支持的开源协议
  "repository": { //对于组件库很有用。让组件库使用者找到你的代码库地址。这个配置项会直接在组件库的npm首页生效
    "type": "git",
    "url": "git+https://github.com/xxxxxxxxxx"
  },
  "devDependencies": { //开发依赖
    "terser-webpack-plugin": "^4.2.0",
    "webpack": "^4.44.0",
    "webpack-cli": "^3.3.12"
  }
}

我们可以为项目的包命名,版本号定义,描述包,关键词,作者,协议什么的都可以添加好,当然,这里实际还可以添加很多东西,需要的小伙伴可以自己去查询下,我们在这里需要注意的是,

  • 在开发依赖里其实最好不要放置我们上面用到的例如打包工具这种东西,不要把测试工具、代码转换器或者打包工具等放在这里,影响大小。

6:书写README.md

README.md就是包的说明书了,这个就在根目录下创建这个文件,然后在里面写说明书就好啦。

当然除了这个还不够,我们把代码上传到github需要.gitignore来让一些没用的文件不要上传,同样,上传到npm也是一样,需要创建一个.npmignore来吧不用上传的文件排除,这个就看各位需求了,就不列举了。

好了:现在我们万事俱备只欠东风了。

7:发布到npm市场

一般发布到npm市场只需要两步,登录,发布

  1. npm login 然后输入npm网站的账号密码进行登录
  2. npm publish发布就好了。

当然这也有坑,大部分情况为啥呢,因为源的问题,npm的源是国外源,而我们日常为了快其实都切换了其他源,所以在发布前,我们要切回到npm原有的源,npm config **set** registry=http://registry.npmjs.org

  • 当然,为了大家方便,我为大家准备了一个sh脚本,一键上传即可。

我们在根目录创建一个文件publish.sh

#!/usr/bin/env bash
npm config get registry 
npm config set registry=http://registry.npmjs.org
echo '请进行登录:'
npm login #登录
echo '===========publish=========='
npm publish #发布
npm config set registry=http://registry.npm.taobao.org
echo '发布完成'
exit

只需要在终端输入 sh ./publish.sh 然后输入你的账号密码邮箱就可以发布啦,当然,第一次的时候会出现文件夹权限不够的情况,这个给文件夹把权限加上就好啦。发布成功大概就是这个样子:

好啦,发布完之后。npm就会有邮箱发到你的邮箱了,然后登录网站就可以看到你发布的包了,然后就去试试吧,一个完整规范的npm公共库就这样完成啦。

sn-console

咱们又回到开始,基于上面的问题,封装了这样一个公共库,目的是为了让日常调试更方便,看看使用吧;

  • npm install sn-console --save
  • import 'sn-console'

只需两部轻松引入到项目之中,因为console本身就是全局对象,所以我们直接就把导出的log挂载到了window上面,我们之间来看看怎么使用吧,其实就是让log可以打印彩色的字体,加标签,让我们更快的看到我们打印的日志,我导出了一个叫log的对象,我们可以直接打印对象看看里面的方法,你也可以直接调用 log.help()方法里面会详细说明。可以在代码里面调用,也可以直接在控制台调用,因为我们已经挂载到了window

  • 基础使用
  1. log是一个对象,分别提供了,log.info(),log.primary,log.success,log.warning,log.danger(),这些方法呢,可以打印一个带标签头的日志,看看效果
let arr = [
            {
                name: 'SNine',
                age: 22
            },
            {
                name: '张三',
                age: 28
            }
        ]
  log.info(arr)
  log.success(arr)
  log.primary(arr)
  log.warning(arr)
  log.danger(arr)

他会打印一个彩色的标签,想想,万黑从中一点绿,是不是可以一眼看到自己打印的日志了呢,当然,如果绿太多了,我们可能又会花了眼,所以这个标签头当然也是可以改变的,我们只需要传入第二个参数,就会改变他的标签名称,来试试吧

log.info(arr,'这是我自己改的标签头')
log.success(arr,'这是我自己改的标签头')
log.primary(arr,'这是我自己改的标签头')
log.warning(arr,'这是我自己改的标签头')
log.danger(arr,'这是我自己改的标签头')

  • 打印图片

打开一些网站的控制台,我们会发现有的网站有欢迎你的图片,所以我也提供了一个**log.img()**的方法可以用来打印图片,需要传入一个连接,就随便在百度找一个吧。

        log.img('https://ss2.bdstatic.com/70cFvnSh_Q1YnxGkpoWK1HF6hhy/it/u=2969235134,2098148338&fm=11&gp=0.jpg')

  • 打印一条分割线

log.line(),有时候自己会console.log('-----------------------------------------------')这样一条线让日志更明显,更好找,这里就直接调用这个方法就会打印一条这样的线,就不做演示了。

  • 清除其他日志

有时候这样的场景,我只想看到某某以后的日志,前面的不想看,那么调用这个方法 log.clear(),调用之后,前面的日志都不会在打印了,后面的日志会基础正常输出。

  • 打印一个欢迎的花漾字,直接看看效果吧,

可以打印出这样的效果,当然纯属娱乐啦,为自己网站定制一个特别的标签也当然很有意思啦,这个功能还不完善,因为把文字转成这样的编码的接口还没有自己开发是别人的,所以还不能够自定义,后面可以加上。

  • 打印一个版权信息,直接看效果吧

打印一个这样的信息放在自己的网站是不是很酷呢,当然,这个呢也还不完善,后面有时间我会把所有的内容变成自定义的方式,更加方便,为自己的网站加个版权吧。

  • 检查自己网页的性能

这个方法呢就比较厉害了,前端性能检测也是一个话题,刚好chrome提供了一个API可以实现,performance,具体的功能大家自行查询,我们的方法非常简单,只需要调用log.performance(),他为你统计了网页的各个时间段时间,具体的自行研究吧。

  • 拦截console.log

类似于前面的那种场景,我是看着都烦,所以,咱们又不可能去删了别人那么多的console.log 所以我们致敬拦截掉console.log只需要调用log.clearAll,你会发现,所有的console日志全部消失了,然后我们开心的使用自己的log库来打印自己的日志就好了,再也不用受他人干扰,当然用完记得删掉这个方法,不然我不保证明天你的队友不打人(手动狗头),同时,这个方法也可以用于判断环境,在生产的时候启动这个方法同样可以做到到生产所有的console消失洛,虽然在打包时候可以去掉,但是这样也是一种简单的实现方法洛。

总结

我们常常在工作中迷失自己的学习方向,常常在想自己的学习方向,怎么学,怎么有效,依我之前,不如就自己造轮子吧,多发布一些自己的公共库,下次再去实现某某功能的时候,必能知其然,知其所以然,发现详细能够百度到的npm发布教程五花八门但是都不够详细,所以闲下来就写了一篇详细的介绍,希望可以帮到你,当然,创作不易,帮到你的话,帮我点个赞吧。