webpack打包之Library打包

panyan.jpg

写在前面

之前写下了《webpack4入门讲解》文集,里面从webapck最基础概念,到一些高级的配置,处理分包等问题,读完后你会对webpack有一个比较清晰的认识,从这一节开始,我们要去学习一些webpack的高级使用实际,在实际开发中,你可能会遇到一些比如打包优化等等方面的内容,这个文集中将详细介绍,同时,为了保证知识涵盖面的广泛,还会将到一些你开发中可能用不到的内容,大家各取所需即可。当然,基础还不扎实的同学,要去学习前面的文集哦,前面的文集可不是各取所需,如果可以,我希望你将它彻底搞懂。
下面进入本文集的第一篇文章

Library打包

什么是“Library”?

所谓Library即“库”,比如我们使用的lodash就是一个“函数库”,比如我们的常用的'antd'、'elementUI'这些就属于“组件库”,在实际的工作中,我们很有可能去封装自己的函数库或者是UI组件库或者是基于某个开源库做二次封装的业务组件库,那么我们是入库针对“库”进行打包的呢?

环境准备
  • 创建一个名为'library'的文件夹,执行npm init -y,初始化一个npm环境。
    生成的package.json如下
{
  "name": "library", // 库的名字
  "version": "1.0.0", // 库的版本
  "description": "", // 库的描述
  "main": "index.js", // 入口
  "scripts": { // npm指令
    "test": "echo \"Error: no test specified\" && exit 1" // 可以删掉,创建我们自己的指令
  },
  "keywords": [],
  "author": "yourname", // 库的作者
  "license": "ISC" // 协议,可以改成‘MIT’开源协议
}
  • 写一个自己的库

在根目录下创建如下文件目录

|--src
  |--math.js
  |--string.js
  |--index.js 

其中内容如下

// math.js
export function add (a, b) {
    return a+b
}
export function minus (a, b) {
    return a-b
}
export function multiply (a, b) {
    return a*b
}
export function division (a, b) {
    return a/b
}
// string.js
export function join(a, b) {
    return a + ' ' + b
}
// index.js
import * as math from './math'
import * as string from './string'
export default { math, string }

上面的代码中,我们就简单的实现了一个自己的库,其中包括加减乘除的数字运算和字符串的拼接,实际上,一个库的开发,就类似于一个业务系统,他也是需要被打包才能被使用,所以我们还需要webpack对其进行打包

  • 安装webpack并创建webpack.config.js配置文件
yarn add webpack webpack-cli -S

webpack.config.js

const path = require('path')

module.exports = {
    mode: 'production',
    entry: './src/index.js',
    output: {
        path: path.resolve(__dirname, 'dist'),
        filename: 'library.js'
    }
}

package.json中增加打包指令

  "scripts": {
    "build": "webpack"
  }
  • 执行打包

我们看到在根目录'dist'文件夹下生成了一个'library.js'的文件,如果是对于我们平常的业务代码,到这一步,我们已经完成了,但是我们是开发一个库的代码,是要给别人用的,别人用的形式可能是下面这样的

import library from 'library' // ESM

const library = require('library') // commonJs

于是我们在配置文件中加入一个配置项如下

module.exports = {
  output: {
    libraryTarget: 'umd'
  }
}

意思是,无论你使用什么样的引入方式,我们打包出来的库都支持。有时候我们还有可能是通过script标签进行引入的

<script src='library.js'></script>
// 在使用的时候,通过library这样的全局变量来使用,就像jquery那样

那么我们还需要在配置项中加入下面的配置

module.exports = {
  output: {
    library: 'library' // 名字随便取,代表我们全局暴露的变量
  }
}
  • 执行打包,打包依然是生成了一个'library.js'的文件,下面我们通过一个简单的html文件来验证一下我们的打包结果,这里就是个html通过script标签引入,然后测试全局变量,自行测试。
关于libraryTarget和library的配置关系

实际上,在做library打包的时候是,libraryTargetlibrary是有一定的关系的,需要配合使用

  • library作为核心,代表要生成一个全局变量
  • libraryTarget意思是这个全局变量挂在哪里,如果是umd,那么二者是没有关系的,如果是this,就代表我们的库不再支持AMD,commonJS,esm等模块形式,而是将全局变量注入到全局的this上面。其中libraryTarget可以取值umdthiswindowglobal(nodeJs下)等值,一般我们在封装一个库的时候,会选择umd

关于libraryTargetlibrary,其实其内容也是比较多的,这里我们只做简单的介绍,如果你的真的需要去打包这样的库的话,再去翻阅相关资料

在Library中使用第三方库

有时候,我们在封装自己的库的时候,不是所有的方法都自己写的,我们也会去引用一些第三方的组件库或者函数库,比如在上面的例子中,我们做下面的代码变更

// string.js
import _ from 'lodash'
export function join(a, b) {
    return _.join([a,b], ' ')
}

这时候打包,也是能正常打包的,但是,library文件却比之前大了很多,这是因为我们打包进了lodash这个库,但是用户在使用我们的库的时候,可能在业务代码中也会引入lodash这个库,这个时候,打包的代码,很可能就会打包出两份lodash,从而中造成一些问题,为了解决这个问题,我们需要这样去配置

externals
module.exports = {
  externals: ['lodash']
}

做了上面配置后,我们发现,我的库打包后又变小了,那么externals的意思是啥呢?就是我们在打包的时候,遇到这个库就忽略他,不要把他打包到代码中,具体的配置,大家可以看一下官网的API,其中,externals可以配置为对象,并且有几个参数,这里我们只讲解commonjsroot,大家就知道怎么回事了

commonjs

我们将配置改成这样

module.exports = {
    externals: {
        lodash: {
            commonjs: 'lodash'
        }
    }
}

上面配置的意思是,当我使用commonjs规范做打包的时候,遇到lodash这个库,我们必须使用'lodash'这个名字,就像这样

const lodash = require('lodash')
const _ = require('lodash') // 这是错误的!!
root
module.exports = {
    externals: {
        lodash: {
            root: '_',
            commonjs: 'lodash'
        }
    }
}

这代表,我们不使用模块化,而是用script标签做引入的话,这时候,我们必须全局注入一个'_'的变量

当然了一般情况下,我们都是直接

module.exports = {
    externals: {
        lodash: 'lodash'
    }
}

意思是,不管是怎么引入,我们都使用'lodash'这个名字。
这里我们只是对library的打包,做了一个相对简单的介绍,实际上,当你要去真正开发一个组件库的时候,其打包文件也是比较复杂的,到时候大家再去学习,这里通过library的打包,让大家知道几个概念和配置项

将包发布到npm

我们将库封装好了以后,一般会将库发布到npm上去,这里就再代价感受一下,将自定义的库发布到npm上

  1. 修改配置文件中的main
"main": "./dist/library.js"

将main改成我们将来要给用户去用的文件

  1. 到npm官网去注册一个npm账号
  2. 根目录下执行npm adduers,添加用户名密码
  3. 运行npm publish,将包发布到npm仓库中,但是,我们的仓库名很容易和线上已有包重名,造成发布失败,这就需要我们把名字起的独特一点,如果你的在cnpm私库下面,还需要有作用域来解决这一问题。
  4. npm install 试试使用的库吧!

写在后面

本文介绍了关于库即Library的打包方式,和一些webpack中比较高级的概念,大家可以试着去写一个自己的库试试哦!