《Webpack5 核心原理与应用实践》学习笔记-> 构建npm包

207 阅读7分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第6天,点击查看活动详情

npm大家都应该很熟悉,包括之前也一直讲npm i [包名],这一次就来构建一个属于自己的npm

开发一个npm

准备工作当然是得新建一个工程,这个工程作为你的npm包的起点,我这里就叫first-npm-lib,老规矩,cd进入该目录下,然后npm init -y生成package.json文件。

这一节是使用webpakc构建npm包,所以还是需要先安装webpack的,npm i -D webpack webpack-cli

先不着急配置webpacknpm包当然是需要有具体功能的,所以我们先写自己的功能代码,开始正式环节。

  • 新建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构建一下看看产出是什么。

image.png

可以看到打包出来的东西会有一个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对于模块化的功能是非常弱的,于是就诞生出来了AMDCommonJS这两大派系的模块化方案,一分派系就难为程序员了,开始想兼容方案,一个包要两个规范都兼容才能有更多的使用量嘛,于是就诞生了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属性控制的。
CommonJSrequire并不是浏览器原本就有的东西,这个一般存在于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应该都看得懂。

devtoolperformanceproductionqualitycomment
(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已经给我们提供好了一系列的配置手段,让我们使用起来毫不费力,就是学习起来东西就有点多了,加油卷。