Skip to content

Commit 877c060

Browse files
Add ReactNative build back, fix base64 serialization (#3251)
1 parent dd1e63c commit 877c060

File tree

9 files changed

+141
-8
lines changed

9 files changed

+141
-8
lines changed

.changeset/shy-forks-speak.md

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
"firebase": minor
3+
"@firebase/firestore": minor
4+
---
5+
6+
Re-adding the ReactNative bundle, which allows Firestore to be used without `btoa`/`atob` Polyfills.

packages/firebase/src/index.rn.ts

+1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import '../database';
2323
// TODO(b/158625454): Storage doesn't actually work by default in RN (it uses
2424
// `atob`). We should provide a RN build that works out of the box.
2525
import '../storage';
26+
import '../firestore';
2627

2728
firebase.registerVersion(name, version, 'rn');
2829

packages/firestore/externs.json

+1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
{
22
"externs" : [
33
"node_modules/@types/node/base.d.ts",
4+
"node_modules/@types/node/globals.d.ts",
45
"node_modules/typescript/lib/lib.es5.d.ts",
56
"node_modules/typescript/lib/lib.dom.d.ts",
67
"node_modules/typescript/lib/lib.es2015.promise.d.ts",

packages/firestore/memory/package.json

+1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
"description": "A memory-only build of the Cloud Firestore JS SDK.",
44
"main": "../dist/index.memory.node.cjs.js",
55
"main-esm2017": "../dist/index.memory.node.esm2017.js",
6+
"react-native": "../dist/index.memory.rn.esm2017.js",
67
"browser": "../dist/index.memory.cjs.js",
78
"module": "../dist/index.memory.esm.js",
89
"esm2017": "../dist/index.memory.esm2017.js",

packages/firestore/package.json

+1
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
},
4444
"main": "dist/index.node.cjs.js",
4545
"main-esm2017": "dist/index.node.esm2017.js",
46+
"react-native": "dist/index.rn.esm2017.js",
4647
"browser": "dist/index.cjs.js",
4748
"module": "dist/index.esm.js",
4849
"esm2017": "dist/index.esm2017.js",

packages/firestore/rollup.config.es2017.js

+31-1
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,36 @@ const browserBuilds = [
103103
}
104104
];
105105

106+
const reactNativeBuildPlugins = [
107+
alias(generateAliasConfig('rn')),
108+
...browserBuildPlugins.slice(1)
109+
];
110+
111+
const reactNativeBuilds = [
112+
// Persistence build
113+
{
114+
input: 'index.rn.ts',
115+
output: {
116+
file: pkg['react-native'],
117+
format: 'es',
118+
sourcemap: true
119+
},
120+
plugins: reactNativeBuildPlugins,
121+
external: resolveBrowserExterns
122+
},
123+
// Memory-only build
124+
{
125+
input: 'index.rn.memory.ts',
126+
output: {
127+
file: path.resolve('./memory', memoryPkg['react-native']),
128+
format: 'es',
129+
sourcemap: true
130+
},
131+
plugins: reactNativeBuildPlugins,
132+
external: resolveBrowserExterns
133+
}
134+
];
135+
106136
// MARK: Node builds
107137

108138
const nodeBuildPlugins = [
@@ -149,4 +179,4 @@ const nodeBuilds = [
149179
}
150180
];
151181

152-
export default [...browserBuilds, ...nodeBuilds];
182+
export default [...browserBuilds, ...reactNativeBuilds, ...nodeBuilds];

packages/firestore/rollup.config.es5.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/**
22
* @license
3-
* Copyright 2018 Google Inc.
3+
* Copyright 2018 Google LLC
44
*
55
* Licensed under the Apache License, Version 2.0 (the "License");
66
* you may not use this file except in compliance with the License.

packages/firestore/src/platform/rn/base64.ts

+16-6
Original file line numberDiff line numberDiff line change
@@ -17,18 +17,28 @@
1717

1818
import { base64 } from '@firebase/util';
1919

20+
// WebSafe uses a different URL-encoding safe alphabet that doesn't match
21+
// the encoding used on the backend.
22+
const WEB_SAFE = false;
23+
2024
/** Converts a Base64 encoded string to a binary string. */
2125
export function decodeBase64(encoded: string): string {
22-
// WebSafe uses a different URL-encoding safe alphabet that doesn't match
23-
// the encoding used on the backend.
24-
return base64.decodeString(encoded, /* webSafe =*/ false);
26+
return String.fromCharCode.apply(
27+
null,
28+
// We use `decodeStringToByteArray()` instead of `decodeString()` since
29+
// `decodeString()` returns Unicode strings, which doesn't match the values
30+
// returned by `atob()`'s Latin1 representation.
31+
base64.decodeStringToByteArray(encoded, WEB_SAFE)
32+
);
2533
}
2634

2735
/** Converts a binary string to a Base64 encoded string. */
2836
export function encodeBase64(raw: string): string {
29-
// WebSafe uses a different URL-encoding safe alphabet that doesn't match
30-
// the encoding used on the backend.
31-
return base64.encodeString(raw, /* webSafe =*/ false);
37+
const bytes: number[] = [];
38+
for (let i = 0; i < raw.length; i++) {
39+
bytes[i] = raw.charCodeAt(i);
40+
}
41+
return base64.encodeByteArray(bytes, WEB_SAFE);
3242
}
3343

3444
/** True if and only if the Base64 conversion functions are available. */
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
/**
2+
* @license
3+
* Copyright 2020 Google LLC
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
import { expect } from 'chai';
19+
20+
import * as rn from '../../../src/platform/rn/base64';
21+
22+
const BASE64_ENCODED = 'GRBoQgKB9LW1';
23+
const BASE64_DECODED = '\u0019\u0010\u0068\u0042\u0002\u0081\u00f4\u00b5\u00b5';
24+
25+
describe('atob', () => {
26+
// eslint-disable-next-line no-restricted-properties
27+
(typeof atob !== 'undefined' ? it : it.skip)(
28+
'decodes with native support',
29+
() => {
30+
const decoded = atob(BASE64_ENCODED);
31+
expect(decoded).to.equal(BASE64_DECODED);
32+
}
33+
);
34+
35+
// eslint-disable-next-line no-restricted-properties
36+
(typeof atob !== 'undefined' ? it : it.skip)(
37+
'roundtrips with native support',
38+
() => {
39+
expect(atob(btoa(BASE64_ENCODED))).to.equal(BASE64_ENCODED);
40+
}
41+
);
42+
43+
it('decodes with polyfill', () => {
44+
const decoded = rn.decodeBase64(BASE64_ENCODED);
45+
expect(decoded).to.equal(BASE64_DECODED);
46+
});
47+
48+
it('roundtrips with polyfill', () => {
49+
expect(rn.encodeBase64(rn.decodeBase64(BASE64_ENCODED))).to.equal(
50+
BASE64_ENCODED
51+
);
52+
});
53+
});
54+
55+
describe('btoa', () => {
56+
// eslint-disable-next-line no-restricted-properties
57+
(typeof btoa !== 'undefined' ? it : it.skip)(
58+
'encodes with native support',
59+
() => {
60+
const encoded = btoa(BASE64_DECODED);
61+
expect(encoded).to.equal(BASE64_ENCODED);
62+
}
63+
);
64+
65+
// eslint-disable-next-line no-restricted-properties
66+
(typeof btoa !== 'undefined' ? it : it.skip)(
67+
'roundtrips with native support',
68+
() => {
69+
expect(atob(btoa(BASE64_DECODED))).to.equal(BASE64_DECODED);
70+
}
71+
);
72+
73+
it('encodes with polyfill', () => {
74+
const encoded = rn.encodeBase64(BASE64_DECODED);
75+
expect(encoded).to.equal(BASE64_ENCODED);
76+
});
77+
78+
it('roundtrips with polyfill', () => {
79+
expect(rn.decodeBase64(rn.encodeBase64(BASE64_DECODED))).to.equal(
80+
BASE64_DECODED
81+
);
82+
});
83+
});

0 commit comments

Comments
 (0)