如何构建适配Node.js与Web的NPM包?及跨环境兼容问题排查
首先得搞清楚你遇到的SyntaxError: Unexpected token import报错根源:Node.js默认对ES模块(import/export)的支持需要特定配置——要么在package.json里加"type": "module",要么你的代码是转译后的CommonJS格式(require/module.exports)。而wpcom-xhr-request能双环境跑,核心是做了环境适配的模块化设计和多入口导出,下面我一步步给你拆解:
一、wpcom-xhr-request是怎么实现双环境适配的?
它的核心思路其实很简单,主要靠两点:
- package.json的环境字段配置:通过
browser、main、module或者更现代的exports字段,给不同环境指定对应的入口文件。比如浏览器环境加载基于XHR的实现,Node.js环境加载基于http/https模块的实现。 - 条件加载/环境隔离:在代码里通过判断全局变量(比如
typeof window !== 'undefined')区分环境,加载对应的请求逻辑;或者直接拆分两个独立的实现文件,让工具自动选择。
另外它可能用了打包工具(比如rollup)生成兼容不同模块系统的产物,但核心逻辑还是环境区分+多入口。
二、不用n8-make实现你的acme-xhr-request
不用Makefile也能搞定,我们用更通用的npm脚本+标准Node.js配置来实现:
1. 先解决模块语法报错
如果你的源码用ES模块(import/export),在package.json里添加:
"type": "module"
这样Node.js会把所有.js文件当作ES模块处理;如果要同时兼容CommonJS,推荐用rollup/esbuild打包成两个版本(ES模块和CommonJS),或者用package.json的exports字段做条件导出。
2. 拆分双环境的请求实现
把代码拆成三个文件:
browser.js:浏览器端基于XHR的实现(直接复用你克隆来的wpcom浏览器逻辑就行)node.js:Node.js端基于http/https模块的实现,比如:import http from 'http'; import https from 'https'; import { URL } from 'url'; export default function nodeRequest(options, callback) { const urlObj = new URL(options.url); const client = urlObj.protocol === 'https:' ? https : http; const req = client.request({ hostname: urlObj.hostname, port: urlObj.port, path: urlObj.pathname + urlObj.search, method: options.method || 'GET', headers: options.headers }, (res) => { let body = ''; res.on('data', chunk => body += chunk); res.on('end', () => { callback(null, { statusCode: res.statusCode, headers: res.headers, body: body }); }); }); req.on('error', err => callback(err)); if (options.body) req.write(options.body); req.end(); }index.js:入口文件,做环境判断或者直接用条件导出(推荐后者)
3. 用package.json的exports字段做标准环境导出
这是Node.js和现代打包工具(webpack/vite)都支持的标准方式,在package.json里加:
"exports": { ".": { "browser": "./browser.js", "node": "./node.js", "default": "./index.js" } }, "main": "./index.js", "module": "./browser.js"
这样:
- 浏览器环境会自动加载
browser.js - Node.js环境会自动加载
node.js - 其他工具会用
default指定的入口
4. 替换Makefile为npm脚本
把Makefile里的构建、测试命令转到package.json的scripts里,比如:
"scripts": { "test:node": "node test/node.test.js", "test:browser": "vite test/browser.test.html", // 或者用karma等工具 "test": "npm run test:node && npm run test:browser" }
之后用npm run test就能跑双环境测试,完全不用Makefile。
5. 测试验证
- Node.js环境:写个测试脚本
test/node.test.js,用import或者require加载你的包,发起请求看是否正常。 - 浏览器环境:在HTML里引入你的包,或者用vite/webpack打包后测试XHR请求。
这样你的acme-xhr-request就能像wpcom-xhr-request一样,同时在Node.js和Web环境里正常运行了。
内容的提问来源于stack exchange,提问作者user3982143

