基于Axios构建NPM库:生成浏览器兼容ESM包遇阻求助
解决基于Axios构建兼容浏览器的ESM包问题
问题描述
我正在基于Axios构建一个NPM库,使用Rollup生成两个打包文件:供浏览器使用的ESM包和供Node.js使用的CJS包。但生成的ESM模块引入了https、path、fs等Node.js内置库,导致该包无法在前端使用。
参考Axios的构建方式,我在package.json的browser字段定义了Node.js内置模块的polyfill映射,但问题仍未解决:
"browser": { "node_modules/axios/lib/adapters/http.js": "node_modules/axios/lib/helpers/null.js", "node_modules/axio/lib/platform/node/index.js": "node_modules/axios/lib/platform/browser/index.js" },
同时尝试使用Rollup插件生成内置模块的polyfill,也没有效果。
我的Rollup配置如下:
// rollup.config.js const resolve = require('@rollup/plugin-node-resolve'); const commonjs = require('@rollup/plugin-commonjs'); const peerDepsExternal = require('rollup-plugin-peer-deps-external'); const typescript = require('@rollup/plugin-typescript'); const dts = require('rollup-plugin-dts'); const json = require('@rollup/plugin-json'); const packageJson = require('./package.json'); export default [ { input: 'src/index.ts', output: [ { file: packageJson.main, format: 'cjs', }, { file: packageJson.module, format: 'esm', }, ], plugins: [ resolve(), commonjs(), json(), peerDepsExternal('./package.json'), typescript({ tsconfig: './tsconfig.json' }), ], }, { input: 'dist/esm/index.d.ts', output: [{ file: 'dist/index.d.ts', format: 'esm' }], plugins: [dts.default()], }, ];
解决方案
1. 修正package.json的browser字段配置
首先修正路径拼写错误(axio少了s),并简化路径配置:
"browser": { "axios/lib/adapters/http.js": "axios/lib/adapters/xhr.js", "axios/lib/platform/node/index.js": "axios/lib/platform/browser/index.js" }
无需写完整的node_modules路径,Rollup会自动解析模块。
2. 安装并配置适配浏览器的Rollup插件
安装必要依赖:
npm install @rollup/plugin-replace rollup-plugin-node-polyfills @rollup/plugin-inject --save-dev
修改Rollup配置,单独区分Node.js和浏览器环境的打包规则:
// rollup.config.js const resolve = require('@rollup/plugin-node-resolve'); const commonjs = require('@rollup/plugin-commonjs'); const peerDepsExternal = require('rollup-plugin-peer-deps-external'); const typescript = require('@rollup/plugin-typescript'); const dts = require('rollup-plugin-dts'); const json = require('@rollup/plugin-json'); const replace = require('@rollup/plugin-replace'); const nodePolyfills = require('rollup-plugin-node-polyfills'); const inject = require('@rollup/plugin-inject'); const packageJson = require('./package.json'); // 公共插件集合 const commonPlugins = [ peerDepsExternal('./package.json'), typescript({ tsconfig: './tsconfig.json' }), json(), resolve({ browser: true, // 启用浏览器环境模块解析 preferBuiltins: false // 不优先使用Node.js内置模块 }), commonjs(), ]; export default [ // Node.js CJS包配置 { input: 'src/index.ts', output: { file: packageJson.main, format: 'cjs', }, plugins: [...commonPlugins], external: Object.keys(packageJson.dependencies || {}) // 标记依赖为外部模块,避免打包进CJS }, // 浏览器ESM包配置 { input: 'src/index.ts', output: { file: packageJson.module, format: 'esm', }, plugins: [ ...commonPlugins, replace({ 'process.env.NODE_ENV': JSON.stringify('production'), preventAssignment: true }), inject({ process: 'rollup-plugin-node-polyfills/process', Buffer: ['buffer', 'Buffer'] }), nodePolyfills({ include: ['http', 'https', 'path', 'fs'] // 按需polyfill Node.js内置模块 }) ], }, // 类型声明打包 { input: 'dist/esm/index.d.ts', output: [{ file: 'dist/index.d.ts', format: 'esm' }], plugins: [dts.default()], }, ];
3. 代码层面避免显式引入Node.js专属模块
确保代码中没有直接引入Axios的Node.js专属模块(比如axios/lib/adapters/http),而是使用Axios默认导出的实例,它会自动根据环境适配对应的适配器。
4. 验证打包结果
执行打包命令后,检查生成的ESM包代码,确认https、fs等模块已被替换为浏览器兼容的实现或polyfill。
内容的提问来源于stack exchange,提问作者Gaurav Thakur
相关产品推荐
相关产品推荐

