问题描述
我正在开发一个 Node-browser (Isomorphic) 库,其中的源代码是用 TypeScript 编写的,然后被转换成 CJS 和 ES 模块。 转译后的代码按原样发送,在发布前未使用模块捆绑器进行捆绑。
我需要使用 node core 的 stream 模块,我打算在浏览器部分使用 stream-browserify 包。
- 在库中使用 Node.js 流或任何特定于节点的库的最佳方法是什么?
- 如何在无需重写相同代码或尽量减少重复的情况下包含流浏览器?
- 我遇到了一些使用 package.json 中的 browser 字段的示例,如下所示 -
"browser" : {
"stream":"stream-browserify";
}
这是如何工作的?
解决方法
您将需要配置用于转换代码以了解已安装模块的任何工具。
如果您不捆绑代码,则意味着您在导入每个单独的文件时加载它(我不确定您如何或打算如何使用 CJS 执行此操作,因为没有 require()
浏览器中的 API)。但是,如果我 import foo from "some-library";
和 some-library
是第三方包,需要加载的 JavaScript 文件需要以某种方式导入。
这意味着三件事:
- 您需要模块的代码,这意味着您需要实际安装它(您将使用
dependencies
中的package.json
散列执行此操作)。 - 您需要能够导入代码。这意味着您的
import
语句需要由您的转译器/捆绑器/等重写。指向可访问的路径。import foo from 'some-library';
需要将'some-library'
翻译成类似node_modules/some-library/src/index.js
的内容。否则浏览器如何知道要加载什么以及从哪里加载? - 您需要对要导入的库的内部执行相同的操作,因为它们还需要重写其导入。
您提到的 browser
哈希将代码中导入的模块名称映射到模块的浏览器友好版本。您列出的示例意味着 require('stream')
在为浏览器编译时变为 require('stream-browserify')
,在为 Node 编译时变为 require('stream')
。
对于上面的 #2 和 #3,TypeScript(或者更确切地说,tsc
)不会为你做这些。 听起来你想要一个像Snowpack这样的工具。但是,有一些事情需要注意。
首先,你不能在浏览器中运行任何 Node 模块,或者至少没有像 Webpack 这样更高级的工具来模拟/重写/替换需要 Node 并且不能的依赖项 在浏览器中运行。如果您导入的模块需要另一个不是浏览器安全的模块,您将不会知道它不是浏览器安全的,直到它在运行时抛出错误(无论是 JS 错误还是来自您的服务器的 404)。
其次,您可能确实想要一个打包器。如果你使用 Node 模块,依赖树会变得很深。如果您的 node_modules/
目录中有 5,000 个 JS 文件,那就是 5,000 个网络请求——其中许多需要串行加载、解析和执行(即,在导入它们的模块加载和解析之后)。像摇树这样的优化离不开打包器:即使是用于生产目的的 Snowpack recommends creating an optimized build。
也就是说,如果您要发布一个包(也就是说,您将其上传到 NPM,而不是将其部署到您自己的服务器),这几乎没有实际意义。只需按照通常的方式编写代码,在 dependencies
中列出您的依赖项,在 browser
中列出浏览器安全的等效项,然后发布您的转译源。实际使用你的库的人会担心如何加载它。如果您不发布到 NPM(也就是说,您自己将这些代码放到网络上),请考虑使用打包程序。打包器并不妨碍您拥有同构库:您可以拥有一个在浏览器和 Node 中运行的单个 JS 文件,或者您可以拥有从同一源编译的两个输出文件(一个浏览器,一个 Node)。您如何实现这一目标取决于您的目标。