# 一、webpack-numbers案例
这里我也不折腾了, 就以官网提供的案例进行讲解吧.
首先让我们明确要做什么事情.
- 本地编写创建一个名为
lindaidai-webpack-numbers的项目(也就是library) - 这个library的功能是导出两个方法, 能实现数字与字符串的互相转换
 - library中用到了lodash这个工具库
 - 将library打包发布到NPM上, 其它用户能够通过
npm install的方式下载使用 - 外部化lodash, 也就是我们library虽然使用了lodash, 但是并不要将它打包到我们的bundle中
 - 用户能通过ES2015模块, CommonJS模块, script脚本引入我们的library并使用它
 
该 library 的使用方式如下:
// ES2015模块引入
import * as webpackNumbers from 'lindaidai-webpack-numbers'
// CommonJS模块引入
var webpackNumbers = require('lindaidai-webpack-numbers')
// ES2015模块和CommonJS模块都是这样调用的:
webpackNumbers.numToWord(2)
// AMD模块引入
require(['lindaidai-webpack-numbers'], function (webpackNumbers) {
  // AMD 模块调用
  webpackNumbers.wordToNum('Two');
})
用户还可以通过 script 标签来加载和使用此 library:
<!doctype html>
<html>
  ...
  <script src="https://unpkg.com/lindaidai-webpack-numbers"></script>
  <script>
    // ...
    // 全局变量
    webpackNumbers.wordToNum('Five')
    // window 对象中的属性
    window.webpackNumbers.wordToNum('Five')
    // ...
  </script>
</html>
# 创建library的项目结构
让我们使用webpack快速的构建一个本地的library.
由于有了之前webpack的基础, 我相信你构建起来应该也会很快.
mkdir lindaidai-webpack-numbers && cd lindaidai-webpack-numbers
npm init -y
cnpm i --save-dev webpack webpack-cli lodash
touch webpack.config.js
mkdir src && cd src
touch index.js
touch ref.json
一顿操作之后, 项目结构变成了这样:
lindaidai-webpack-numbers
	|- /node_modules
	|- /src
		|- index.js
		|- ref.json
	|- package.json
	|- webpack.config.js
之后来简单的编写一下文件中的代码:
src/ref.json:
[{
        "num": 1,
        "word": "One"
    },
    {
        "num": 2,
        "word": "Two"
    },
    {
        "num": 3,
        "word": "Three"
    },
    {
        "num": 4,
        "word": "Four"
    },
    {
        "num": 5,
        "word": "Five"
    },
    {
        "num": 0,
        "word": "Zero"
    }
]
src/index.js:
import _ from 'lodash';
import numRef from './ref.json';
export function numToWord(num) {
    return _.reduce(numRef, (accum, ref) => {
        return num === ref.num ? ref.word : accum
    })
}
export function wordToNum(word) {
    return _.reduce(numRef, (accum, ref) => {
        return ref.word === word && word.toLowerCase() ? ref.num : accum;
    }, -1);
};
webpack.config.js:
module.exports = {
  entry: './src/index.js',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'webpack-numbers.js'
  }
};
# 配置webpack.config.js
编写完成上面👆几个文件之后, 打包之后生成的dist目录就只有一个webpack-numbers.js文件:
/dist
	|- webpack.numbers.js
但是我们注意到生成的js中包含了lodash:
lindaidai@LinDaiDaideMacBook-Pro lindaidai-webpack-numbers % npm run build
> lindaidai-webpack-numbers@1.0.0 build /Users/lindaidai/codes/webpack/lindaidai-webpack-numbers
> webpack
Hash: e49f78747376a068a282
Version: webpack 4.41.5
Time: 1544ms
Built at: 2020-02-10 6:57:59 PM
             Asset      Size  Chunks             Chunk Names
+ webpack-numbers.js  72.4 KiB       0  [emitted]  main
所以导致webpack-number.js非常大.
# 外部化lodash(配置externals)
因此对于这种我们额外引入的module, 我们更倾向于把 lodash 当作 peerDependency。也就是说,用户应该已经将 lodash 安装好.
所以,你可以放弃对外部 library 的控制,而是将控制权让给使用 library 的用户。
这个功能需要靠externals配置:
webpack.config.js:
module.exports = {
  entry: './src/index.js',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'webpack-numbers.js'
-  }
+  },
+  externals: {
+  	lodash: {
+  		commonjs: 'lodash',
+  		commonjs2: 'lodash',
+  		amd: 'lodash',
+  		root: '_'
+  	}
  }
};
这意味着你的 library 需要一个名为
lodash的依赖,这个依赖在用户的环境中必须存在且可用。
# 暴露library
因为我们编写的library可能会在不同的执行环境中用到,例如 CommonJS,AMD,Node.js 或者作为一个全局变量.
所以为了实现这个功能, 我们首先需要在oupout中添加library属性:
webpack.config.js:
  var path = require('path');
  module.exports = {
    entry: './src/index.js',
    output: {
      path: path.resolve(__dirname, 'dist'),
      filename: 'webpack-numbers.js',
+     library: 'webpackNumbers'
    },
    externals: {
      lodash: {
        commonjs: 'lodash',
        commonjs2: 'lodash',
        amd: 'lodash',
        root: '_'
      }
    }
  };
添加了library属性是为了将library在打包之后的bundle文件中暴露一个名为webpackNumbers的全局变量.
但是还需要指定我们的library在怎样的环境中使用.
这依靠于libraryTarget属性, 它可以控制library如何以不同方式暴露的选项.
主要有以下几个值:
- 变量:作为一个全局变量,通过 
script标签来访问(libraryTarget:'var')。 - this:通过 
this对象访问(libraryTarget:'this')。 - window:通过 
window对象访问,在浏览器中(libraryTarget:'window')。 - UMD:在 AMD 或 CommonJS 的 
require之后可访问, 也就是以上几种环境都可以访问(libraryTarget:'umd') 
如果设置了 library 但没设置 libraryTarget,则 libraryTarget 默认为 var
所以在此处我希望在所有的环境中都能使用, 则只要设置libraryTarget: 'umd':
  var path = require('path');
  module.exports = {
    entry: './src/index.js',
    output: {
      path: path.resolve(__dirname, 'dist'),
      filename: 'webpack-numbers.js',
      library: 'webpackNumbers',
+     libraryTarget: 'umd'
    },
    externals: {
      lodash: {
        commonjs: 'lodash',
        commonjs2: 'lodash',
        amd: 'lodash',
        root: '_'
      }
    }
  };
# 发布至NPM
现在我们希望的是将打包之后的dist文件与这整个项目一起发布到NPM上.
所以我们需要执行打包命令让library项目目录结构变为:
lindaidai-webpack-numbers
	|- /dist
		|- webpack.numbers.js
	|- /src
		|- index.js
		|- ref.json
	|- package.json
	|- webpack.config.js
(如果你的项目没有配置打包命令的话需要在package.json中配置一个脚本命令"build": "webpack", 这样你就可以执行npm run build指令进行打包了)
# 登录npm
npm adduser //创建用户(如果你没有npm账号的话)
or
npm login //登录用户
可以使用:
npm whoami
检测用户是否登录上了npm
# 安装publish
首先需要安装publish
npm i -g publish
# 发布library
由于我们之前提到了你需要将整个library通过bundle中的webpack.numbers.js暴露出去, 所以你还需要修改package.json中的"main"属性:
{
  ...
  "main": "dist/webpack-numbers.js",
  ...
}
这样整体的package.json需要修改成如下:
{
    "name": "lindaidai-webpack-numbers",
    "version": "1.0.0",
+   "description": "This is a LinDaiDai's packages",
+   "main": "dist/webpack-numbers.js",
+   "private": false,
    "scripts": {
+        "build": "webpack"
    },
    "keywords": [],
    "author": "",
    "license": "ISC",
    "devDependencies": {
        "lodash": "^4.17.15",
        "webpack": "^4.41.5",
        "webpack-cli": "^3.3.10"
    }
}
现在你就可以在项目根目录下执行指令来发布library了:
npm publish
成功之后应该会提示:
+lindaidai-webpack-numbers@1.0.0
并且此时你是可以在 unpkg.com 中找到你发布的library的.
若是你编写的模块是第一次发布的,则直接使用指令npm publish就可以了
若是第二次,则需要在package.json中修改一下version,如修改为1.0.1,然后再次执行npm publish就OK了。
如果你在发布的时候报了如下的错误, 这是由于包名重复了, 也就是你发布的包在NPM上已经有人用了, 你换个名字就可以了:
npm ERR! code E403
npm ERR! 403 403 Forbidden - PUT https://registry.npmjs.org/mini-vm - You do not have permission to publish "webpack-numbers". Are you logged in as the correct user?
npm ERR! 403 In most cases, you or one of your dependencies are requestingnpm ERR! 403 a package version that is forbidden by your security policy.
npm ERR! A complete log of this run can be found in:
npm ERR!     F:\node\rely\node_cache\_logs\2020-02-07T08_30_57_238Z-debug.log
还有以下几点需要你注意的:
确保自己是登录了npm的
确保自己的npm的邮箱被激活了
命名不能太简单,最后要有自己的标志,太简单可能是别人已经用过的名字你就不能发布成功,也不要有数字
如果是要再次推送同一个项目记得修改该项目版本号。
具体关于NPM包的发布可以看我之前的一篇文章: 《NPM-在npm上发布模块》
# 使用发布的library
成功将自己的library发布到NPM上了之后, 让我们来用个案例测试下吧.
(案例GitHub地址: LinDaiDai/webpack-basic)
在项目的根目录下执行命令来安装library:
npm i --save-dev lindaidai-webpack-numbers
接下里在项目中使用它:
// ES6
import * as lindaiWebpackNumbers from 'lindaidai-webpack-numbers'
// CommonJS
// var lindaiWebpackNumbers = require('lindaidai-webpack-numbers')
console.log(lindaiWebpackNumbers.numToWord(2)) // Two
引入时命名可以随意, 不一定要是lindaidiWebpackNumbers.