# 一、webpack-numbers案例

这里我也不折腾了, 就以官网提供的案例进行讲解吧.

首先让我们明确要做什么事情.

  1. 本地编写创建一个名为lindaidai-webpack-numbers的项目(也就是library)
  2. 这个library的功能是导出两个方法, 能实现数字与字符串的互相转换
  3. library中用到了lodash这个工具库
  4. 将library打包发布到NPM上, 其它用户能够通过npm install的方式下载使用
  5. 外部化lodash, 也就是我们library虽然使用了lodash, 但是并不要将它打包到我们的bundle中
  6. 用户能通过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

还有以下几点需要你注意的:

  1. 确保自己是登录了npm的

  2. 确保自己的npm的邮箱被激活了

  3. 命名不能太简单,最后要有自己的标志,太简单可能是别人已经用过的名字你就不能发布成功,也不要有数字

  4. 如果是要再次推送同一个项目记得修改该项目版本号。

具体关于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.

阅读全文