webpack实现一个简单的npm包并发布

webpack踩坑日记

Posted by Xshellv on 2022-07-24

本文主要为了记录 webpack5 打包 bundle 并发布过程中踩过坑。

webpack 配置

这里主要列出了 webpack.config 中的关键点,这里比较坑的点是 externals,左边是排除的包名,右边是 xshellv-hooks 在实际场景中引入所在项目的包名,这里如果写成大写的 React 会发现打包后的代码中有 require('React') 的写法,因此会出现找不到 react 的问题。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
module.exports = merge(common(), {
mode: "production",
devtool: false,
output: {
path: path.resolve(ROOT_PATH, "./bundle"),
filename: "js/index.js",
// 引入的umd全局包名
library: "xshellv-hooks",
// 设置打包类型,参照webpack配置介绍
libraryTarget: "umd",
},
target: "web",
// 发布npm包需要排除react,否则重复引用React会有问题
externals: {
react: "react",
},

// 专门存放优化打包的配置
optimization: {
runtimeChunk: false,
minimize: true,
minimizer: [
new CssMinimizerPlugin(),
// JS压缩
new TerserPlugin({
extractComments: false, // 去除所有注释
terserOptions: {
compress: { pure_funcs: ["console.log"] }, // 去除所有console.log函数
},
}),
],
// 代码分割,这里关闭只生成一个主入口index.js
// splitChunks: {
// chunks: 'all',
// minSize: 0,
// },
},
});

其中 entry 的js文件大致如下,这里引入配置省略:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import useMount from "./LifeCycle/useMount";
import useUnmount from "./LifeCycle/useUnmount";
import useBoolean from "./State/useBoolean";
import useSetState from "./State/useSetState";
import useToggle from "./State/useToggle";
import useDebounceFn from "./Effect/useDebounceFn";
import useThrottleFn from "./Effect/useThrottleFn";
import useLatest from "./Advanced/useLatest";

export {
useMount,
useUnmount,
useBoolean,
useToggle,
useLatest,
useSetState,
useDebounceFn,
useThrottleFn,
};

package.json

关键点在于 name 以及 main 设置,此外需要将 react 以及 react-dom 的引入从 dependencies 移动到 peerDependencies 当中,目的是为了 production 环境不把 react 打包进 bundle/index.js, 并提示引入当前包的项目需保证 react 不能低于某个版本,否则无法正常使用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
{
"name": "xshellv-hooks", // npm包名
"version": "1.0.17", // npm版本号
"main": "bundle/js/index.js", // 主入口
"module": "bundle/js/index.js",
"types": "dist/index.d.ts",
"author": "xshellv",
"license": "MIT",
"scripts": {
"webpack:build": "npm run clean:bundle && cross-env NODE_ENV=production webpack --config ./scripts/config/webpack.npm.js",
"prepare": "husky install",
"dumi:dev": "dumi dev",
"commitlint": "commitlint -E HUSKY_GIT_PARAMS",
"build-ts": "ttsc -p tsconfig.build.json",
"clean:dist": "rimraf ./dist",
"clean:bundle": "rimraf ./bundle",
"build": "npm run clean:dist && npm run build-ts",
"release": "npm version patch && npm publish --registry https://registry.npmjs.org/"
},
"dependencies": {
"classnames": "2.3.1",
"dayjs": "1.10.8",
"lodash": "^4.17.21",
"redux": "4.1.2"
},
"peerDependencies": {
"react": ">=16.8.0",
"react-dom": ">=16.8.0"
},
"browserslist": [">0.2%", "not dead", "ie >= 9", "not op_mini all"],
"lint-staged": {
"*.{js,jsx,ts,tsx}": ["eslint --fix --quiet"]
}
}

如何使用

引入 umd 包名字(这里和 package.jsonname 保持一致)

1
import { useDebounceFn } from "xshellv-hooks";

参考文章