前言
之前的文章有提到 npm 模块的组成和发布,最近手头有一个第三方 sdk 的开发,使用 lerna 进行 npm 包的维护,使用 ts 进行开发和测试。
当然 sdk 的打包工具使用了 rollup,这里不对 rollup 和 webpack 进行介绍和比较,vue 和 react 也是使用 rullup ,社区有一大推这方面内容的介绍和教程,下面我们开始细说当 rollup 遇见 axios 时发生的一些故事。
代码准备
目录结构如下:
╰─➤ tree -L 2 -I node_modules
.
├── babel.config.js
├── build
│ ├── index.js
│ └── rollup.config.js
├── index.ts
├── package-lock.json
├── package.json
├── src
│ └── index.ts
└── tsconfig.json
// package.json
{
"name": "rollup-test",
"version": "0.1.0",
"private": true,
"main": "index.js",
"scripts": {
"build": "tsc -d && tsc && npm run build:cjs && npm run build:es && npm run build:umd",
"build:cjs": "cross-env TARGET=cjs node build/index.js",
"build:es": "cross-env TARGET=es node build/index.js",
"build:umd": "cross-env TARGET=umd node build/index.js"
},
"dependencies": {
"cross-env": "^5.2.0",
"@babel/runtime": "^7.4.4",
"@babel/core": "^7.4.4",
"@babel/plugin-transform-runtime": "^7.4.4",
"@babel/preset-env": "^7.4.4",
"magic-string": "^0.25.1",
"rollup": "^1.11.3",
"rollup-plugin-babel": "^4.3.2",
"rollup-plugin-commonjs": "^9.3.4",
"rollup-plugin-json": "^4.0.0",
"rollup-plugin-node-builtins": "^2.1.2",
"rollup-plugin-node-globals": "^1.4.0",
"rollup-plugin-node-resolve": "^4.2.4",
"rollup-plugin-terser": "^4.0.4",
"standard-version": "^6.0.1",
"typescript": "^3.1.6"
},
"devDependencies": {
"axios": "^0.19.0"
}
}
// rollup.config.js
"use strict";
const commonjs = require("rollup-plugin-commonjs");
const resolve = require("rollup-plugin-node-resolve");
const babel = require("rollup-plugin-babel");
const { terser } = require("rollup-plugin-terser");
const json = require("rollup-plugin-json");
const inputOptions = {
plugins: [
resolve(),
commonjs({
browser: true
}),
babel({
exclude: ["node_modules/**"],
runtimeHelpers: true
}),
terser(),
json()
]
};
const outputOptions = {
exports: "named"
};
module.exports = { inputOptions, outputOptions };
// src/index.ts
import axios from "axios";
async function testRollup() {
console.log("test");
await axios.get("");
}
export default testRollup;
思路过程
运行 npm run build 得到如下结果 :
╰─➤ npm run build
> rollup-axios-test@1.0.0 build /Users/leiliao/ShopeeWorkspace/demoWorkspace/rollup-axios
> tsc && node build/index.js
'http' is imported by node_modules/axios/lib/adapters/http.js, but could not be resolved – treating it as an external dependency
'https' is imported by node_modules/axios/lib/adapters/http.js, but could not be resolved – treating it as an external dependency
'url' is imported by node_modules/axios/lib/adapters/http.js, but could not be resolved – treating it as an external dependency
'zlib' is imported by node_modules/axios/lib/adapters/http.js, but could not be resolved – treating it as an external dependency
'http' is imported by commonjs-external-http, but could not be resolved – treating it as an external dependency
'https' is imported by commonjs-external-https, but could not be resolved – treating it as an external dependency
'url' is imported by commonjs-external-url, but could not be resolved – treating it as an external dependency
'zlib' is imported by commonjs-external-zlib, but could not be resolved – treating it as an external dependency
'url' is imported by node_modules/follow-redirects/index.js, but could not be resolved – treating it as an external dependency
'http' is imported by node_modules/follow-redirects/index.js, but could not be resolved – treating it as an external dependency
'https' is imported by node_modules/follow-redirects/index.js, but could not be resolved – treating it as an external dependency
'assert' is imported by node_modules/follow-redirects/index.js, but could not be resolved – treating it as an external dependency
'assert' is imported by commonjs-external-assert, but could not be resolved – treating it as an external dependency
'stream' is imported by node_modules/follow-redirects/index.js, but could not be resolved – treating it as an external dependency
'stream' is imported by commonjs-external-stream, but could not be resolved – treating it as an external dependency
'tty' is imported by node_modules/debug/src/node.js, but could not be resolved – treating it as an external dependency
'tty' is imported by commonjs-external-tty, but could not be resolved – treating it as an external dependency
'util' is imported by node_modules/debug/src/node.js, but could not be resolved – treating it as an external dependency
'util' is imported by commonjs-external-util, but could not be resolved – treating it as an external dependency
'os' is imported by node_modules/supports-color/index.js, but could not be resolved – treating it as an external dependency
'os' is imported by commonjs-external-os, but could not be resolved – treating it as an external dependency
根据以上错误修改 rollUp 配置,添加 external 字段
"use strict";
const commonjs = require("rollup-plugin-commonjs");
const resolve = require("rollup-plugin-node-resolve");
const babel = require("rollup-plugin-babel");
const { terser } = require("rollup-plugin-terser");
const json = require("rollup-plugin-json");
const inputOptions = {
plugins: [
resolve(),
commonjs({
browser: true
}),
babel({
exclude: ["node_modules/**"],
runtimeHelpers: true
}),
terser(),
json()
],
external: [
"http",
"https",
"url",
"assert",
"stream",
"tty",
"util",
"os",
"zlib"
],
};
const outputOptions = {
exports: "named"
};
module.exports = { inputOptions, outputOptions };
打包结果如下
> ts-vuex-demo@0.1.0 build:umd /Users/leiliao/ShopeeWorkspace/demoWorkspace/rollup-axios
> cross-env TARGET=umd node build/index.js
No name was provided for external module 'http' in output.globals – guessing 'http'
No name was provided for external module 'https' in output.globals – guessing 'https'
No name was provided for external module 'url' in output.globals – guessing 'url'
No name was provided for external module 'assert' in output.globals – guessing 'assert'
No name was provided for external module 'stream' in output.globals – guessing 'stream'
No name was provided for external module 'tty' in output.globals – guessing 'tty'
No name was provided for external module 'util' in output.globals – guessing 'util'
No name was provided for external module 'os' in output.globals – guessing 'os'
No name was provided for external module 'zlib' in output.globals – guessing 'zlib'
Creating a browser bundle that depends on Node.js built-in modules ('http', 'https', 'url', 'assert', 'stream', 'tty', 'util', 'os' and 'zlib'). You might need to include https://www.npmjs.com/package/rollup-plugin-node-builtins
在打包 umd 格式的代码时出现提示,安装 rollup-plugin-node-builtins,并在 rollup 中使用。
"use strict";
const commonjs = require("rollup-plugin-commonjs");
const resolve = require("rollup-plugin-node-resolve");
const babel = require("rollup-plugin-babel");
const { terser } = require("rollup-plugin-terser");
const json = require("rollup-plugin-json");
const builtins = require("rollup-plugin-node-builtins");
const inputOptions = {
plugins: [
resolve(),
builtins(),
commonjs({
browser: true
}),
babel({
exclude: ["node_modules/**"],
runtimeHelpers: true
}),
terser(),
json()
]
};
const outputOptions = {
exports: "named"
};
module.exports = { inputOptions, outputOptions };
打包得到如下信息
Circular dependency: node_modules/rollup-plugin-node-builtins/src/es6/readable-stream/duplex.js -> node_modules/rollup-plugin-node-builtins/src/es6/readable-stream/readable.js -> node_modules/rollup-plugin-node-builtins/src/es6/readable-stream/duplex.js
Circular dependency: node_modules/rollup-plugin-node-builtins/src/es6/readable-stream/duplex.js -> node_modules/rollup-plugin-node-builtins/src/es6/readable-stream/writable.js -> node_modules/rollup-plugin-node-builtins/src/es6/readable-stream/duplex.js
为啥用官方提示的工具也不行呢?让我们试一下打出来的包是否能使用(笔者一开始以为这只是 warnning),我们使用 npm link 运行当前项目
╰─➤ npm link
audited 3216 packages in 6.82s
found 26 moderate severity vulnerabilities
run `npm audit fix` to fix them, or `npm audit` for details
/Users/leiliao/.nvm/versions/node/v10.15.3/lib/node_modules/rollup-test -> /Users/leiliao/....../demoWorkspace/rollup-axios
然后在一个新项目中引用它
╰─➤ npm link rollup-test
/Users/leiliao/ShopeeWorkspace/otherEWokspace/ts-vuex-demo/node_modules/rollup-test -> /Users/leiliao/.nvm/versions/node/v10.15.3/lib/node_modules/rollup-test -> /Users/leiliao/ShopeeWorkspace/demoWorkspace/rollup-axios
//main.ts
import test from 'rollup-axios-test';
test();
运行目标项目,发现报错
[HMR] Waiting for update signal from WDS...
index.mjs?395a:1 Uncaught ReferenceError: global is not defined
at eval (index.mjs?395a:1)
at Module.../../demoWorkspace/rollup-axios/dist/index.mjs (app.js:915)
at __webpack_require__ (app.js:767)
at fn (app.js:130)
at eval (main.ts:18)
at Module../src/main.ts (app.js:5423)
at __webpack_require__ (app.js:767)
at fn (app.js:130)
at Object.1 (app.js:5509)
at __webpack_require__ (app.js:767)
说明打包失败!
我们换用 fetch api ,并重新弄打包
// src/index.ts
import axios from "axios";
async function testRollup() {
console.log("test");
// await axios.get("");
const response = await fetch("", {
method: "GET"
});
await response.text();
}
export default testRollup;
不出现报错,那我们还是使用 fetch api 吧。
如果使用了 jest 测试代码 ,可以使用 jest-fetch.
难道 rollup 打包不能支持 axios 吗 ? 答案是错误的。看一条 issue 。
看到有同学跟我一样 弃用了 axios ,改用 fetch ,但是更好的解决办法。
Rollup will need some tweaks if we want Axios working and bundled successfully. Without the tweaks the Rollup bundle will be interrupted with errors caused by Axios.
Adding a small entry on the Axios README.md will spare a few hours of Googling desperate solutions.
We'll need to add the below to the Rollup configuration:
// package.json
"rollup-plugin-node-resolve": "3.0",
"rollup-plugin-json": "2.3"
// Rollup configuration
plugins: [
rollupNodeResolve({ jsnext: true, preferBuiltins: true, browser: true }),
rollupJson(),
...
]
我们改用配置如下
"use strict";
const commonjs = require("rollup-plugin-commonjs");
const resolve = require("rollup-plugin-node-resolve");
const babel = require("rollup-plugin-babel");
const { terser } = require("rollup-plugin-terser");
const json = require("rollup-plugin-json");
const inputOptions = {
plugins: [
resolve({ jsnext: true, preferBuiltins: true, browser: true }),
commonjs({
browser: true
}),
babel({
exclude: ["node_modules/**"],
runtimeHelpers: true
}),
terser(),
json()
]
};
const outputOptions = {
exports: "named"
};
module.exports = { inputOptions, outputOptions };
在 src/index.ts 中重新启用 axios,运行打包命令。
> rollup-test@0.1.0 build:umd /Users/leiliao/ShopeeWorkspace/demoWorkspace/rollup-axios
> cross-env TARGET=umd node build/index.js
node-resolve: setting options.jsnext is deprecated, please override options.mainFields instead
这时候已经能够成功运行了,但是 options.jsnext is deprecated , 所以我们查看一下 rollup-plugin-node-resolve 的文档
mainFields: ['module', 'main'], // Default: ['module', 'main']
// DEPRECATED: use "mainFields" instead
// use "module" field for ES6 module if possible
module: true, // Default: true
// DEPRECATED: use "mainFields" instead
// use "jsnext:main" if possible
// legacy field pointing to ES6 module in third-party libraries,
// deprecated in favor of "pkg.module":
// - see: https://github.com/rollup/rollup/wiki/pkg.module
jsnext: true, // Default: false
// DEPRECATED: use "mainFields" instead
// use "main" field or index.js, even if it's not an ES6 module
// (needs to be converted from CommonJS to ES6)
// – see https://github.com/rollup/rollup-plugin-commonjs
main: true, // Default: true
// some package.json files have a "browser" field which specifies
// alternative files to load for people bundling for the browser. If
// that's you, either use this option or add "browser" to the
// "mainfields" option, otherwise pkg.browser will be ignored
browser: true, // Default: false
修改配置如下:
resolve({ mainFields: ["jsnext", "preferBuiltins", "browser"] }),
打包,得到一个干净的控制台,成功使用 axios。
源码
总结
遇到问题其实可以不着急马上解决,可以先思考,再沉淀,最后动手去做,效率会快很多。