npm
大家都应该很熟悉,包括之前也一直讲npm i [包名]
,这一次就来构建一个属于自己的npm
。
开发一个npm
库
准备工作当然是得新建一个工程,这个工程作为你的npm
包的起点,我这里就叫first-npm-lib
,老规矩,cd
进入该目录下,然后npm init -y
生成package.json
文件。
这一节是使用webpakc
构建npm
包,所以还是需要先安装webpack
的,npm i -D webpack webpack-cli
。
先不着急配置webpack
,npm
包当然是需要有具体功能的,所以我们先写自己的功能代码,开始正式环节。
- 新建
src
目录。 src
下新建index.js
文件,就随便写一个数组乱序吧。
export function disorderedList(list = []) { const result = [].slice.call(list); return result.sort(_ => { return Math.random() - Math.random(); }) }
完了之后就是专心
webpack
的配置了
- 新建
webpack.config.js
,里面还是老一套的东西,入口出口啥的,不过需要注意的是出口不能像之前那样随意了。
const path = require("path"); module.exports = { mode: "development", entry: "./src/index.js", output: { filename: "[name].js", path: path.join(__dirname, "./dist"), library: { name: "firstNpmLib", type: "umd", }, } };
可以看到上面的出口配置多了一个library
的配置,先不管这个配置是干嘛的,先直接npx webpack
构建一下看看产出是什么。
可以看到打包出来的东西会有一个webpackUniversalModuleDefinition
的立即执行函数,这就是library.type
的作用了,下面是官方文档中的原话,文档在这:library。
output.library.type
配置将库暴露的方式。
- 类型:
string
类型默认包括'var'
、'module'
、'assign'
、'assign-properties'
、'this'
、'window'
、'self'
、'global'
、'commonjs'
、'commonjs2'
、'commonjs-module'
、'commonjs-static'
、'amd'
、'amd-require'
、'umd'
、'umd2'
、'jsonp'
以及'system'
,除此之外也可以通过插件添加。
这里就着重讲一下umd
umd
就是一种规范,是一个时代的产物,因为在es6
没出来之前,js
对于模块化的功能是非常弱的,于是就诞生出来了AMD
、CommonJS
这两大派系的模块化方案,一分派系就难为程序员了,开始想兼容方案,一个包要两个规范都兼容才能有更多的使用量嘛,于是就诞生了umd
,可以说是非常的“有趣”,所以这里使用的就是umd
。
使用了这种方案就可以这样使用自己开发的包了:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> </body> <script src="./dist/main.js"></script> <script> // Webpack 会将模块直接挂载到全局对象上 const list = firstNpmLib.disorderedList([1, 2, 3, 4, 5, 6, 7]); console.log(list); </script> <script type="module"> // ES Module import './dist/main.js'; const list1 = firstNpmLib.disorderedList([1, 2, 3, 4, 5, 6, 7]); console.log(list1); // CommonJS // require('./dist/main.js'); // const list2 = firstNpmLib.disorderedList([1, 2, 3, 4, 5, 6, 7]); // console.log(list2); </script> </html>
注意:上面的
ES Module
是直接引用的,不是import {xxx} form 'xxx'
,因为里面是立即执行函数,会暴露一个firstNpmLib
作为全局变量来使用,这个firstNpmLib
就是output.library.name
属性控制的。
CommonJS
的require
并不是浏览器原本就有的东西,这个一般存在于node
环境中,所以这里我屏蔽了。
排除第三方依赖包
上面是我们自己开发的库,有时候难免会使用到第三方的依赖库,这个时候如果将第三方的依赖库打包到我们的包里面,无疑是会增加我们包的体积,如果用户也是使用了这个库,那么这个库在用户的代码中会存在双份,所以需要排除。
index.js
代码修改如下
import {shuffle} from 'lodash'; export function disorderedList(list = []) { return shuffle(list) }
现在记录一下打包前的文件体积,执行npx webpack
看一下打包后的文件体积,也可以看看两者中的却别,都可以很明显的看到包的体积变大了很多。
这里就需要使用external
属性来排除依赖库,修改webpack
配置如下:
const path = require("path"); module.exports = { // 省略之前的配置 externals: { lodash: { commonjs: 'lodash', // 移除 exports['xxx'] 这样写的方式 commonjs2: 'lodash', // 移除 exports.xxx 这样写的方式 amd: 'lodash', // 移除 amd 的使用方式 root: '_', // 移除 全局变量挂载的方式 }, } };
然后再执行npx webpack
看看生成之后的产物吧,当然这样生成的东西不能独立运作哦,也就是上面讲过的使用方法或报错。
生成Sourcemap
Sourcemap
就是对编译后的代码提供调试可定位到对应代码行的记录文件,例如vue
开发环境下,报错了可以很轻易的定位到报错的代码行,而在生产环境下就不可以了,因为生产环境下没有Sourcemap
。
Sourcemap
的使用很简单,webpack
配置增加一个devtool
就可以了。
module.exports = { // 省略之前的配置 devtool: 'source-map' };
devtool
的可选值如下,下面来自官方文档:devtool,下面的翻译来自机翻。这里简单解释一下:
构建就是初次打包速度,重建就二次打包(有缓存的情况下)的速度。
production
指的是是否适合生产环境quality
指的是Sourcemap
文件生成的地方。comment
应该都看得懂。
devtool | performance | production | quality | comment |
(none) | 构建:最快 重建:最快 | 是的 | 捆 | 具有最高性能的生产构建的推荐选择。 |
eval |
构建:快速 重建:最快 | 不 | 生成 | 具有最高性能的开发构建的推荐选择。 |
eval-cheap-source-map |
构建:好的 重建:快 | 不 | 变身 | 开发构建的权衡选择。 |
eval-cheap-module-source-map |
构建:慢 重建:快 | 不 | 原线 | 开发构建的权衡选择。 |
eval-source-map |
构建:最慢的 重建:好的 | 不 | 原来的 | 使用高质量 SourceMap 进行开发构建的推荐选择。 |
cheap-source-map |
构建:好的 重建:慢 | 不 | 变身 | |
cheap-module-source-map |
构建:慢 重建:慢 | 不 | 原线 | |
source-map |
构建:最慢 重建:最慢 | 是的 | 原来的 | 具有高质量 SourceMap 的生产构建的推荐选择。 |
inline-cheap-source-map |
构建:好的 重建:慢 | 不 | 变身 | |
inline-cheap-module-source-map |
构建:慢 重建:慢 | 不 | 原线 | |
inline-source-map |
构建:最慢 重建:最慢 | 不 | 原来的 | 发布单个文件时的可能选择 |
eval-nosources-cheap-source-map |
构建:好的 重建:快 | 不 | 变身 | 不包括源代码 |
eval-nosources-cheap-module-source-map |
构建:慢 重建:快 | 不 | 原线 | 不包括源代码 |
eval-nosources-source-map |
构建:最慢的 重建:好的 | 不 | 原来的 | 不包括源代码 |
inline-nosources-cheap-source-map |
构建:好的 重建:慢 | 不 | 变身 | 不包括源代码 |
inline-nosources-cheap-module-source-map |
构建:慢 重建:慢 | 不 | 原线 | 不包括源代码 |
inline-nosources-source-map |
构建:最慢 重建:最慢 | 不 | 原来的 | 不包括源代码 |
nosources-cheap-source-map |
构建:好的 重建:慢 | 不 | 变身 | 不包括源代码 |
nosources-cheap-module-source-map |
构建:慢 重建:慢 | 不 | 原线 | 不包括源代码 |
nosources-source-map |
构建:最慢 重建:最慢 | 是的 | 原来的 | 不包括源代码 |
hidden-nosources-cheap-source-map |
构建:好的 重建:慢 | 不 | 变身 | 无参考,不包括源代码 |
hidden-nosources-cheap-module-source-map |
构建:慢 重建:慢 | 不 | 原线 | 无参考,不包括源代码 |
hidden-nosources-source-map |
构建:最慢 重建:最慢 | 是的 | 原来的 | 无参考,不包括源代码 |
hidden-cheap-source-map |
构建:好的 重建:慢 | 不 | 变身 | 没有参考 |
hidden-cheap-module-source-map |
构建:慢 重建:慢 | 不 | 原线 | 没有参考 |
hidden-source-map |
构建:最慢 重建:最慢 | 是的 | 原来的 | 没有参考。仅将 SourceMap 用于错误报告目的时的可能选择 |
完成之后在执行npx webpack
看看生成的内容,可以看到多了一个main.js.map
文件,这个就是Sourcemap
文件。
其他
上面的这些就已经把webpack
的配置基本上都搞定了,除非你还需要有其他的需求,例如加上.css
,例如使用.ts
就需要配置一些额外的loader
了,其他的就是一些小技巧。
.npmignore
可以忽略某些文件不提交到npm
。package.json
中可以指定包的入口文件main
属性可以指定包的入口。package.json
中指定module
属性可以指定es module
的入口,可以和上面的main
并存。package.json
中指定repository
属性可以指定仓库地址。package.json
中指定home
属性可以指定主页地址。
就这么多吧,瑞思拜。
总结
npm
包好像就是要让各种平台和规范都能使用,并没有什么特殊的,加之webpack
已经给我们提供好了一系列的配置手段,让我们使用起来毫不费力,就是学习起来东西就有点多了,加油卷。