Skip to content

Commit 273ea2a

Browse files
fix: provide both browser and node cjs bundles (#2457)
### 🎯 Goal Although it rarely makes sense to SSR chat, import `stream-chat-react` on server ideally shouldn't fail. ### πŸ›  Implementation details We now build two CJS bundles: one with node-specific dependencies (esbuild `platform: 'node'`), one with browser-specific dependencies (esbuild `platform: 'browser'`). The node version is exposed as a `"node"` export in package.json, so frameworks like Next.js should prefer it for SSR. --------- Co-authored-by: Anton Arnautov <[email protected]>
1 parent 4e60c07 commit 273ea2a

File tree

5 files changed

+45
-15
lines changed

5 files changed

+45
-15
lines changed

β€Ž.github/workflows/size.ymlβ€Ž

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,4 @@ jobs:
1818
- uses: preactjs/compressed-size-action@v2
1919
with:
2020
repo-token: '${{ secrets.GITHUB_TOKEN }}'
21-
pattern: './dist/**/*.{js,css,json}'
21+
pattern: './dist/**/*.{js,cjs,css,json}'

β€Žpackage.jsonβ€Ž

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,26 +10,44 @@
1010
"url": "https://github.com/GetStream/stream-chat-react.git"
1111
},
1212
"types": "dist/index.d.ts",
13-
"main": "dist/index.cjs.js",
13+
"main": "dist/index.node.cjs",
1414
"module": "dist/index.js",
1515
"jsdelivr": "./dist/browser.full-bundle.min.js",
1616
"exports": {
1717
".": {
1818
"types": "./dist/index.d.ts",
19-
"require": "./dist/index.cjs.js",
20-
"import": "./dist/index.js",
19+
"node": {
20+
"require": "./dist/index.node.cjs",
21+
"import": "./dist/index.js"
22+
},
23+
"browser": {
24+
"require": "./dist/index.browser.cjs",
25+
"import": "./dist/index.js"
26+
},
2127
"default": "./dist/index.js"
2228
},
2329
"./emojis": {
2430
"types": "./dist/plugins/Emojis/index.d.ts",
25-
"require": "./dist/plugins/Emojis/index.cjs.js",
26-
"import": "./dist/plugins/Emojis/index.js",
31+
"node": {
32+
"require": "./dist/plugins/Emojis/index.node.cjs",
33+
"import": "./dist/plugins/Emojis/index.js"
34+
},
35+
"browser": {
36+
"require": "./dist/plugins/Emojis/index.browser.cjs",
37+
"import": "./dist/plugins/Emojis/index.js"
38+
},
2739
"default": "./dist/plugins/Emojis/index.js"
2840
},
2941
"./mp3-encoder": {
3042
"types": "./dist/plugins/encoders/mp3.d.ts",
31-
"require": "./dist/plugins/encoders/mp3.cjs.js",
32-
"import": "./dist/plugins/encoders/mp3.js",
43+
"node": {
44+
"require": "./dist/plugins/encoders/mp3.node.cjs",
45+
"import": "./dist/plugins/encoders/mp3.js"
46+
},
47+
"browser": {
48+
"require": "./dist/plugins/encoders/mp3.browser.cjs",
49+
"import": "./dist/plugins/encoders/mp3.js"
50+
},
3351
"default": "./dist/plugins/encoders/mp3.js"
3452
},
3553
"./dist/css/*": {
@@ -242,7 +260,7 @@
242260
"test": "jest",
243261
"types": "tsc --noEmit --skipLibCheck false",
244262
"validate-translations": "node scripts/validate-translations.js",
245-
"validate-cjs": "node scripts/validate-cjs-bundle.cjs",
263+
"validate-cjs": "concurrently 'node scripts/validate-cjs-node-bundle.cjs' 'node scripts/validate-cjs-browser-bundle.cjs'",
246264
"semantic-release": "semantic-release",
247265
"browse-examples": "ladle serve",
248266
"e2e": "playwright test",

β€Žscripts/bundle.mjsβ€Ž

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,16 +31,26 @@ const deps = Object.keys({
3131
});
3232
const external = deps.filter((dep) => !bundledDeps.includes(dep));
3333

34+
/** @type esbuild.BuildOptions */
3435
const cjsBundleConfig = {
3536
entryPoints: [sdkEntrypoint, emojiEntrypoint, mp3EncoderEntrypoint],
3637
bundle: true,
3738
format: 'cjs',
38-
platform: 'browser',
3939
target: 'es2020',
4040
external,
4141
outdir: outDir,
42-
entryNames: '[dir]/[name].cjs',
42+
outExtension: { '.js': '.cjs' },
4343
sourcemap: 'linked',
4444
};
4545

46-
await esbuild.build(cjsBundleConfig);
46+
// We build two CJS bundles: for browser and for node. The latter one can be
47+
// used e.g. during SSR (although it makes little sence to SSR chat, but still
48+
// nice for import not to break on server).
49+
const bundles = ['browser', 'node'].map((platform) =>
50+
esbuild.build({
51+
...cjsBundleConfig,
52+
entryNames: `[dir]/[name].${platform}`,
53+
platform,
54+
}),
55+
);
56+
await Promise.all(bundles);

β€Žscripts/validate-cjs-bundle.cjsβ€Ž renamed to β€Žscripts/validate-cjs-browser-bundle.cjsβ€Ž

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
// As the community transitions to ESM, we can easily break our CJS bundle.
22
// This smoke test can help to detect this early.
33

4-
// First, set up minimal browser-like environment:
54
const { JSDOM } = require('jsdom');
65
const dom = new JSDOM('', {
76
url: 'https://localhost',
@@ -15,5 +14,4 @@ for (const key of Object.keys(window)) {
1514
}
1615
}
1716

18-
// Then, try importing our CJS bundle:
19-
require('../dist/index.cjs.js');
17+
require('../dist/index.browser.cjs');
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
// As the community transitions to ESM, we can easily break our CJS bundle.
2+
// This smoke test can help to detect this early.
3+
4+
require('../dist/index.node.cjs');

0 commit comments

Comments
Β (0)