跨包传递 Firestore (v9) 实例
Passing Firestore (v9) instance across packages
我正在尝试将一些 Firestore 操作写入一个单独的包中,以便可以在不同的 Web 应用程序中导入和重复使用。我正在用不同的包构建一个 monorepo 并且我正在尝试使用 Firebase v9 用于以下示例:
从 packageA
我正在定义和导出一个 getPosts(db)
函数,该函数接受一个 Firestore
对象和 returns 一些来自给定数据库的帖子
// in 'packageA'
import { collection, getDocs, Firestore } from 'firebase/firestore';
export const getPosts = async (db: Firestore) => {
console.log('Passed in db: ', db); // This correctly prints the passed in Firestore object
try {
const postsCollection = collection(db, 'posts'); // This function will throw
const querySnapshot = await getDocs(postsCollection);
return querySnapshot.docs.map((doc) => doc.data());
} catch (e) {
console.error('Error reading posts: ', e);
}
}
在网络应用中,我正在初始化 Firebase 应用并导出 Firestore 实例
// firebase.js in 'web-app-1'
import { initializeApp } from 'firebase/app';
import { getFirestore } from 'firebase/firestore';
const firebaseConfig = { /* my Firebase config */ };
export const app = initializeApp(firebaseConfig);
export const db = getFirestore(app);
然后我尝试在组件中使用包中的 getPosts
函数...
// App.js in 'web-app-1'
import { db } from './firebase.js';
import { getPosts } from 'packageA';
let posts;
async function loadPosts() {
try {
posts = await getPosts(db);
} catch (e) {
console.error(e);
}
}
loadPosts(); // throws an error
但我从 collection(db, 'posts')
调用
中收到以下错误
Error reading posts: Expected first argument to collection() to be a CollectionReference, a DocumentReference or FirebaseFirestore
即使传入的数据库在控制台中正确打印(形成 getPosts
函数)
注意: 如果我复制整个 getPosts
函数并直接在网络应用程序中使用它(即不从另一个包导入它)那么它可以正常工作获取帖子。
它看起来像是版本 9 的错误,并且该方法正在尝试使用 Firebase 实时数据库而不是 Firestore,因此该方法正在为集合发送错误。
使用该函数时似乎忽略了它是 Firestore 的事实,所以我会直接将其发送到 Firebase support,因为包的形成方式似乎是主要问题。
我仔细查看了一下,发现 一个类似的问题也可以解决我的问题。
基本上我必须做的是在 packageA
中将 Firebase 指定为 peerDependency
并且 不将其包含在最终包 中。使用 packageA
的 Web 应用程序将包含 Firebase 作为常规 dependency
。
因此 package.json
文件如下所示
在实用程序包中
{
"name": "packageA",
"peerDependencies": {
"firebase": "^9.6.3"
}
}
然后在网络应用程序中
{
"name": "web-app-1",
"dependencies": {
"firebase": "^9.6.3",
}
}
这种方法对我的用例也很有意义,因为初始化 Firebase 应用程序的 Web 应用程序(而且只有 Web 应用程序)会将其包含在其捆绑包中。但是我可以想象,在其他一些用例中,这不是一个可能的解决方案。
尽管如此,我已按照建议将我的问题提交给 Firebase 支持,这是他们的答复:
We have received some similar cases and we are already working to solve this. However, it can take a while due the workload of the engineering team, please, be patient.
我目前遇到了同样的问题。解决方法是直接通过捆绑器导入文件。
请记住,这不是最佳选择,因为我必须再次在本机项目中安装包,因此需要一些手动维护
项目结构
- 应用
- 原生
- 网络
- 包
- 工具
这确保我的应用程序使用 native/node_modules/
中的 firebase 实例和包
Metro.config.js
`
const { getDefaultConfig } = require("@expo/metro-config");
const path = require("path");
const projectRoot = __dirname;
const workspaceRoot = path.resolve(__dirname, "../..");
const config = getDefaultConfig(__dirname);
const extraNodeModules = {
'@aim/utils': path.resolve(__dirname + '/../../packages/utils'),
};
const watchFolders = [
path.resolve(__dirname + '/../../packages/utils')
];
config.watchFolders = [workspaceRoot];
config.resolver.nodeModulesPath = [
path.resolve(projectRoot, "node_modules"),
path.resolve(workspaceRoot, "node_modules"),
];
module.exports = {
transformer: {
getTransformOptions: async () => ({
transform: {
experimentalImportSupport: false,
inlineRequires: false,
},
}),
},
resolver: {
extraNodeModules: new Proxy(extraNodeModules, {
get: (target, name) =>
//redirects dependencies referenced from common/ to local node_modules
name in target ? target[name] : path.join(process.cwd(), `node_modules/${name}`),
}),
},
watchFolders,
};
// module.exports = config;
`
让类型发挥作用(原生)
tsconfig.json
`
{
"compilerOptions": {
"allowSyntheticDefaultImports": true,
"jsx": "react-native",
"lib": ["dom", "esnext"],
"moduleResolution": "node",
"noEmit": true,
"skipLibCheck": true,
"resolveJsonModule": true,
"strict": true,
"baseUrl": ".",
"paths": {
"@aim/utils/*": ["../../packages/utils/*"]
}
},
}
`
我正在尝试将一些 Firestore 操作写入一个单独的包中,以便可以在不同的 Web 应用程序中导入和重复使用。我正在用不同的包构建一个 monorepo 并且我正在尝试使用 Firebase v9 用于以下示例:
从 packageA
我正在定义和导出一个 getPosts(db)
函数,该函数接受一个 Firestore
对象和 returns 一些来自给定数据库的帖子
// in 'packageA'
import { collection, getDocs, Firestore } from 'firebase/firestore';
export const getPosts = async (db: Firestore) => {
console.log('Passed in db: ', db); // This correctly prints the passed in Firestore object
try {
const postsCollection = collection(db, 'posts'); // This function will throw
const querySnapshot = await getDocs(postsCollection);
return querySnapshot.docs.map((doc) => doc.data());
} catch (e) {
console.error('Error reading posts: ', e);
}
}
在网络应用中,我正在初始化 Firebase 应用并导出 Firestore 实例
// firebase.js in 'web-app-1'
import { initializeApp } from 'firebase/app';
import { getFirestore } from 'firebase/firestore';
const firebaseConfig = { /* my Firebase config */ };
export const app = initializeApp(firebaseConfig);
export const db = getFirestore(app);
然后我尝试在组件中使用包中的 getPosts
函数...
// App.js in 'web-app-1'
import { db } from './firebase.js';
import { getPosts } from 'packageA';
let posts;
async function loadPosts() {
try {
posts = await getPosts(db);
} catch (e) {
console.error(e);
}
}
loadPosts(); // throws an error
但我从 collection(db, 'posts')
调用
Error reading posts: Expected first argument to collection() to be a CollectionReference, a DocumentReference or FirebaseFirestore
即使传入的数据库在控制台中正确打印(形成 getPosts
函数)
注意: 如果我复制整个 getPosts
函数并直接在网络应用程序中使用它(即不从另一个包导入它)那么它可以正常工作获取帖子。
它看起来像是版本 9 的错误,并且该方法正在尝试使用 Firebase 实时数据库而不是 Firestore,因此该方法正在为集合发送错误。
使用该函数时似乎忽略了它是 Firestore 的事实,所以我会直接将其发送到 Firebase support,因为包的形成方式似乎是主要问题。
我仔细查看了一下,发现
基本上我必须做的是在 packageA
中将 Firebase 指定为 peerDependency
并且 不将其包含在最终包 中。使用 packageA
的 Web 应用程序将包含 Firebase 作为常规 dependency
。
因此 package.json
文件如下所示
在实用程序包中
{
"name": "packageA",
"peerDependencies": {
"firebase": "^9.6.3"
}
}
然后在网络应用程序中
{
"name": "web-app-1",
"dependencies": {
"firebase": "^9.6.3",
}
}
这种方法对我的用例也很有意义,因为初始化 Firebase 应用程序的 Web 应用程序(而且只有 Web 应用程序)会将其包含在其捆绑包中。但是我可以想象,在其他一些用例中,这不是一个可能的解决方案。
尽管如此,我已按照建议将我的问题提交给 Firebase 支持,这是他们的答复:
We have received some similar cases and we are already working to solve this. However, it can take a while due the workload of the engineering team, please, be patient.
我目前遇到了同样的问题。解决方法是直接通过捆绑器导入文件。
请记住,这不是最佳选择,因为我必须再次在本机项目中安装包,因此需要一些手动维护
项目结构
- 应用
- 原生
- 网络
- 包
- 工具
这确保我的应用程序使用 native/node_modules/
Metro.config.js
`
const { getDefaultConfig } = require("@expo/metro-config");
const path = require("path");
const projectRoot = __dirname;
const workspaceRoot = path.resolve(__dirname, "../..");
const config = getDefaultConfig(__dirname);
const extraNodeModules = {
'@aim/utils': path.resolve(__dirname + '/../../packages/utils'),
};
const watchFolders = [
path.resolve(__dirname + '/../../packages/utils')
];
config.watchFolders = [workspaceRoot];
config.resolver.nodeModulesPath = [
path.resolve(projectRoot, "node_modules"),
path.resolve(workspaceRoot, "node_modules"),
];
module.exports = {
transformer: {
getTransformOptions: async () => ({
transform: {
experimentalImportSupport: false,
inlineRequires: false,
},
}),
},
resolver: {
extraNodeModules: new Proxy(extraNodeModules, {
get: (target, name) =>
//redirects dependencies referenced from common/ to local node_modules
name in target ? target[name] : path.join(process.cwd(), `node_modules/${name}`),
}),
},
watchFolders,
};
// module.exports = config;
`
让类型发挥作用(原生)
tsconfig.json `
{
"compilerOptions": {
"allowSyntheticDefaultImports": true,
"jsx": "react-native",
"lib": ["dom", "esnext"],
"moduleResolution": "node",
"noEmit": true,
"skipLibCheck": true,
"resolveJsonModule": true,
"strict": true,
"baseUrl": ".",
"paths": {
"@aim/utils/*": ["../../packages/utils/*"]
}
},
}
`