Saya ingin membuat beberapa Fungsi Awan untuk Firebase dan menempatkan mereka semua pada waktu yang sama dari satu proyek. Saya juga ingin memisahkan setiap fungsi ke dalam sebuah file terpisah. Saat ini saya dapat membuat beberapa fungsi jika saya menempatkan mereka berdua di index.js seperti:
exports.foo = functions.database.ref('/foo').onWrite(event => {
...
});
exports.bar = functions.database.ref('/bar').onWrite(event => {
...
});
Namun saya ingin menempatkan foo dan bar dalam file terpisah. Saya mencoba ini:
/functions
|--index.js (blank)
|--foo.js
|--bar.js
|--package.json
mana foo.js ini
exports.foo = functions.database.ref('/foo').onWrite(event => {
...
});
dan bar.js ini
exports.bar = functions.database.ref('/bar').onWrite(event => {
...
});
Apakah ada cara untuk mencapai hal ini tanpa menempatkan semua fungsi di index.js?
Ah, Fungsi Awan untuk Firebase memuat modul node biasanya, jadi ini bekerja
struktur:
/functions
|--index.js
|--foo.js
|--bar.js
|--package.json
index.js:
const functions = require('firebase-functions');
const fooModule = require('./foo');
const barModule = require('./bar');
exports.foo = functions.database.ref('/foo').onWrite(fooModule.handler);
exports.bar = functions.database.ref('/bar').onWrite(barModule.handler);
foo.js:
exports.handler = (event) => {
...
};
bar.js:
exports.handler = (event) => {
...
};
Jawaban oleh @jasonsirota sangat membantu. Tapi ini mungkin berguna untuk melihat lebih rinci kode, terutama dalam kasus HTTP dipicu fungsi.
Menggunakan struktur yang sama seperti di @jasonsirota's menjawab, katakanlah anda ingin memiliki dua terpisah HTTP fungsi trigger dalam dua file yang berbeda:
struktur direktori:
/functions
|--index.js
|--foo.js
|--bar.js
|--package.json`
index.js:
'use strict';
const fooFunction = require('./foo');
const barFunction = require('./bar');
// Note do below initialization tasks in index.js and
// NOT in child functions:
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
const database = admin.database();
// Pass database to child functions so they have access to it
exports.fooFunction = functions.https.onRequest((req, res) => {
fooFunction.handler(req, res, database);
});
exports.barFunction = functions.https.onRequest((req, res) => {
barFunction.handler(req, res, database);
});
foo.js:
exports.handler = function(req, res, database) {
// Use database to declare databaseRefs:
usersRef = database.ref('users');
...
res.send('foo ran successfully');
}
bar.js:
exports.handler = function(req, res, database) {
// Use database to declare databaseRefs:
usersRef = database.ref('users');
...
res.send('bar ran successfully');
}
Update: doc Ini harus help, jawaban saya adalah lebih tua dari ini dok.
Berikut adalah bagaimana saya personnally melakukannya dengan ketangkasan:
/functions
|--src
|--index.ts
|--http-functions.ts
|--main.js
|--db.ts
|--package.json
|--tsconfig.json
Mari saya jelaskan ini dengan memberikan dua peringatan untuk membuat ini bekerja:
Untuk point nomor 2 I'm tidak yakin mengapa. Kedua anda harus menghormati saya konfigurasi index, utama dan db persis (setidaknya untuk mencobanya).
indeks.ts : berkaitan dengan ekspor. Aku menemukannya cleaner untuk membiarkan indeks.ts berurusan dengan ekspor.
// main must be before functions
export * from './main';
export * from "./http-functions";
utama.ts: Berkaitan dengan inisialisasi.
import { config } from 'firebase-functions';
import { initializeApp } from 'firebase-admin';
initializeApp(config().firebase);
export * from "firebase-functions";
db.ts: hanya reexporting db sehingga namanya lebih pendek dari database ()
import { database } from "firebase-admin";
export const db = database();
http-fungsi.ts
// db must be imported like this
import { db } from './db';
// you can now import everything from index.
import { https } from './index';
// or (both work)
// import { https } from 'firebase-functions';
export let newComment = https.onRequest(createComment);
export async function createComment(req: any, res: any){
db.ref('comments').push(req.body.comment);
res.send(req.body.comment);
}
Dengan Node 8 LTS sekarang tersedia dengan Awan/Firebase Fungsi anda dapat melakukan hal berikut dengan penyebaran operator:
"engines": {
"node": "8"
},
const functions = require("firebase-functions");
const admin = require("firebase-admin");
admin.initializeApp();
module.exports = {
...require("./lib/foo.js"),
// ...require("./lib/bar.js") // add as many as you like
};
const functions = require("firebase-functions");
const admin = require("firebase-admin");
exports.fooHandler = functions.database
.ref("/food/{id}")
.onCreate((snap, context) => {
let id = context.params["id"];
return admin
.database()
.ref(`/bar/${id}`)
.set(true);
});
Dalam kasus dengan Babel/Aliran akan terlihat seperti ini:
.
├── /build/ # Compiled output for Node.js 6.x
├── /src/ # Application source files
│ ├── db.js # Cloud SQL client for Postgres
│ ├── index.js # Main export(s)
│ ├── someFuncA.js # Function A
│ ├── someFuncA.test.js # Function A unit tests
│ ├── someFuncB.js # Function B
│ ├── someFuncB.test.js # Function B unit tests
│ └── store.js # Firebase Firestore client
├── .babelrc # Babel configuration
├── firebase.json # Firebase configuration
└── package.json # List of project dependencies and NPM scripts
src/index.js
- ekspor Utama(s)export * from './someFuncA.js';
export * from './someFuncB.js';
src/db.js
- Cloud SQL Client untuk Postgresimport { Pool } from 'pg';
import { config } from 'firebase-functions';
export default new Pool({
max: 1,
user: '<username>',
database: '<database>',
password: config().db.password,
host: `/cloudsql/${process.env.GCP_PROJECT}:<region>:<instance>`,
});
src/store.js
- Firebase Firestore Klienimport firebase from 'firebase-admin';
import { config } from 'firebase-functions';
firebase.initializeApp(config().firebase);
export default firebase.firestore();
src/someFuncA.js
- Fungsiimport { https } from 'firebase-functions';
import db from './db';
export const someFuncA = https.onRequest(async (req, res) => {
const { rows: regions } = await db.query(`
SELECT * FROM regions WHERE country_code = $1
`, ['US']);
res.send(regions);
});
src/someFuncB.js
- Fungsi Bimport { https } from 'firebase-functions';
import store from './store';
export const someFuncB = https.onRequest(async (req, res) => {
const { docs: regions } = await store
.collection('regions')
.where('countryCode', '==', 'US')
.get();
res.send(regions);
});
.babelrc
{
"presets": [["env", { "targets": { "node": "6.11" } }]],
}
firebase.json
{
"functions": {
"source": ".",
"ignore": [
"**/node_modules/**"
]
}
}
paket.json
{
"name": "functions",
"verson": "0.0.0",
"private": true,
"main": "build/index.js",
"dependencies": {
"firebase-admin": "^5.9.0",
"firebase-functions": "^0.8.1",
"pg": "^7.4.1"
},
"devDependencies": {
"babel-cli": "^6.26.0",
"babel-core": "^6.26.0",
"babel-jest": "^22.2.2",
"babel-preset-env": "^1.6.1",
"jest": "^22.2.2"
},
"scripts": {
"test": "jest --env=node",
"predeploy": "rm -rf ./build && babel --out-dir ./build src",
"deploy": "firebase deploy --only functions"
}
}
$ yarn install # Install project dependencies
$ yarn test # Run unit tests
$ yarn deploy # Deploy to Firebase
Untuk tetap sederhana (tetapi tidak bekerja), saya pribadi telah terstruktur kode saya seperti ini.
Tata letak
├── /src/
│ ├── index.ts
│ ├── foo.ts
│ ├── bar.ts
| ├── db.ts
└── package.json
foo.ts
import * as functions from 'firebase-functions';
export const fooFunction = functions.database()......... {
//do your function.
}
export const someOtherFunction = functions.database().......... {
// do the thing.
}
bar.ts
import * as functions from 'firebase-functions';
export const barFunction = functions.database()......... {
//do your function.
}
export const anotherFunction = functions.database().......... {
// do the thing.
}
db.ts
import * as admin from 'firebase-admin';
import * as functions from 'firebase-functions';
export const firestore = admin.firestore();
export const realtimeDb = admin.database();
indeks.ts
import * as admin from 'firebase-admin';
import * as functions from 'firebase-functions';
admin.initializeApp(functions.config().firebase);
// above codes only needed if you use firebase admin
export * from './foo';
export * from './bar';
Bekerja untuk direktori dari setiap tingkat bersarang. Hanya mengikuti pola-pola di dalam direktori juga.
kredit untuk @zaidfazil jawaban
Untuk tetap sederhana (tetapi tidak bekerja), saya pribadi telah terstruktur kode saya seperti ini.
Tata letak
├── /src/
│ ├── index.ts
│ ├── foo.ts
│ ├── bar.ts
└── package.json
foo.ts
export const fooFunction = functions.database()......... {
//do your function.
}
export const someOtherFunction = functions.database().......... {
// do the thing.
}
bar.ts
export const barFunction = functions.database()......... {
//do your function.
}
export const anotherFunction = functions.database().......... {
// do the thing.
}
indeks.ts
import * as fooFunctions from './foo';
import * as barFunctions from './bar';
module.exports = {
...fooFunctions,
...barFunctions,
};
Bekerja untuk direktori dari setiap tingkat bersarang. Hanya mengikuti pola-pola di dalam direktori juga.
Format ini memungkinkan anda entry-point untuk menemukan fungsi tambahan file, dan ekspor masing-masing fungsi dalam masing-masing file, secara otomatis.
Titik Masuk Utama Skrip
Menemukan semua .js file dalam fungsi folder, dan ekspor masing-masing fungsi yang diekspor dari masing-masing file.
const fs = require('fs');
const path = require('path');
// Folder where all your individual Cloud Functions files are located.
const FUNCTIONS_FOLDER = './scFunctions';
fs.readdirSync(path.resolve(__dirname, FUNCTIONS_FOLDER)).forEach(file => { // list files in the folder.
if(file.endsWith('.js')) {
const fileBaseName = file.slice(0, -3); // Remove the '.js' extension
const thisFunction = require(`${FUNCTIONS_FOLDER}/${fileBaseName}`);
for(var i in thisFunction) {
exports[i] = thisFunction[i];
}
}
});
Contoh Ekspor dari Beberapa Fungsi dari salah Satu File
const functions = require('firebase-functions');
const query = functions.https.onRequest((req, res) => {
let query = req.query.q;
res.send({
"You Searched For": query
});
});
const searchTest = functions.https.onRequest((req, res) => {
res.send({
"searchTest": "Hi There!"
});
});
module.exports = {
query,
searchTest
}
http diakses endpoint yang tepat bernama
✔ functions: query: http://localhost:5001/PROJECT-NAME/us-central1/query
✔ functions: helloWorlds: http://localhost:5001/PROJECT-NAME/us-central1/helloWorlds
✔ functions: searchTest: http://localhost:5001/PROJECT-NAME/us-central1/searchTest
Salah satu file
Jika anda hanya memiliki beberapa file-file tambahan (misalnya hanya satu), anda dapat menggunakan:
const your_functions = require('./path_to_your_functions');
for (var i in your_functions) {
exports[i] = your_functions[i];
}
bigcodenerd.org garis's sederhana pola arsitektur dalam rangka untuk memiliki metode yang dipisahkan ke dalam file yang berbeda dan diekspor dalam satu baris dalam index.js file.
Arsitektur untuk proyek dalam contoh ini adalah sebagai berikut:
projectDirectory
index.js
const admin = require('firebase-admin');
const podcast = require('./podcast');
const profile = require('./profile');
admin.initializeApp();
exports.getPodcast = podcast.getPodcast();
exports.removeProfile = profile.removeProfile();
podcast.js
const functions = require('firebase-functions');
exports.getPodcast = () => functions.https.onCall(async (data, context) => {
...
return { ... }
});
Pola yang sama akan digunakan untuk removeProfile
metode dalam profile file.
Ada cara yang cukup baik untuk mengatur semua fungsi awan untuk jangka panjang. Saya melakukan ini baru-baru ini dan itu bekerja dengan sempurna.
Apa yang saya lakukan adalah mengatur setiap fungsi awan dalam folder terpisah berdasarkan pemicu akhir. Setiap fungsi awan filename berakhir dengan *.f.js
. Misalnya, jika anda telah onCreate
dan onUpdate
pemicu pada pengguna/{id}/dokumen/{documentId}
kemudian membuat dua file onCreate.f.js
dan onUpdate.f.js
pada direktori fungsi/user/dokumen/
dan fungsi anda akan bernama userDocumentOnCreate
dan userDocumentOnUpdate
masing-masing. (1)
Berikut ini adalah contoh struktur direktori:
functions/
|----package.json
|----index.js
/----user/
|-------onCreate.f.js
|-------onWrite.f.js
/-------document/
|------------onCreate.f.js
|------------onUpdate.f.js
/----books/
|-------onCreate.f.js
|-------onUpdate.f.js
|-------onDelete.f.js
const functions = require('firebase-functions');
const admin = require('firebase-admin');
const db = admin.database();
const documentsOnCreate = functions.database
.ref('user/{userId}/document/{documentId}')
.onCreate((snap, context) => {
// your code goes here
});
exports = module.exports = documentsOnCreate;
const glob = require("glob");
const camelCase = require('camelcase');
const admin = require('firebase-admin');
const serviceAccount = require('./path/to/ServiceAccountKey.json');
try {
admin.initializeApp({ credential: admin.credential.cert(serviceAccount),
databaseURL: "Your database URL" });
} catch (e) {
console.log(e);
}
const files = glob.sync('./**/*.f.js', { cwd: __dirname });
for (let f = 0, fl = files.length; f < fl; f++) {
const file = files[f];
const functionName = camelCase(file.slice(0, -5).split('/'));
if (!process.env.FUNCTION_NAME || process.env.FUNCTION_NAME === functionName) {
exports[functionName] = require(file);
}
}
(1): Anda dapat menggunakan nama apapun yang anda inginkan. Untuk saya, onCreate.f.js, onUpdate.f.js dll. tampaknya lebih relevan untuk jenis pemicu mereka.
Jadi saya ini proyek yang memiliki latar belakang fungsi dan http fungsi. Saya juga harus menjalani tes untuk pengujian unit. CI/CD akan membuat hidup anda jauh lebih mudah ketika menjalankan fungsi awan
|-- package.json
|-- cloudbuild.yaml
|-- functions
|-- index.js
|-- background
| |-- onCreate
| |-- index.js
|-- create.js
|
|-- http
| |-- stripe
| |-- index.js
| |-- payment.js
|-- utils
|-- firebaseHelpers.js
|-- test
|-- ...
|-- package.json
Catatan: utils/
folder untuk berbagi kode antara fungsi
Di sini anda hanya dapat mengimpor semua fungsi yang anda butuhkan dan menyatakan mereka. Tidak perlu memiliki logika di sini. Itu membuatnya bersih menurut saya. ``javascript memerlukan('modul-alias/mendaftar'); const fungsi = require('firebase-fungsi');
const onCreate = require('@latar belakang/onCreate'); const onDelete = require('@latar belakang/onDelete'); const onUpdate = require('@latar belakang/onUpdate');
const tours = require('@http/tur'); const garis = require('@http/stripe');
const docPath = 'tur/{tourId}';
modul.ekspor.onCreate = fungsi.firestore.dokumen(docPath).onCreate(onCreate); modul.ekspor.onDelete = fungsi.firestore.dokumen(docPath).onDelete(onDelete); modul.ekspor.onUpdate = fungsi.firestore.dokumen(docPath).onUpdate(onUpdate);
modul.ekspor.tur = fungsi.https.onRequest(tur); modul.ekspor.stripe = fungsi.https.onRequest(stripe); ``
Bagaimana tentang memiliki berkesinambungan integrasi dan penyebaran setiap kali anda mendorong perubahan ke repo? Anda dapat memilikinya dengan menggunakan google google cloud membangun. It's gratis sampai titik tertentu :) Check this link.
./cloudbuild.yaml ``yaml langkah-langkah:
substitusi: _FIREBASE_TOKEN: tidak ada ``
Saya menggunakan vanilla JS bootloader untuk auto-mencakup semua fungsi yang ingin saya gunakan.
├── /functions
│ ├── /test/
│ │ ├── testA.js
│ │ └── testB.js
│ ├── index.js
│ └── package.json
index.js (bootloader)
/**
* The bootloader reads all directories (single level, NOT recursively)
* to include all known functions.
*/
const functions = require('firebase-functions');
const fs = require('fs')
const path = require('path')
fs.readdirSync(process.cwd()).forEach(location => {
if (!location.startsWith('.')) {
location = path.resolve(location)
if (fs.statSync(location).isDirectory() && path.dirname(location).toLowerCase() !== 'node_modules') {
fs.readdirSync(location).forEach(filepath => {
filepath = path.join(location, filepath)
if (fs.statSync(filepath).isFile() && path.extname(filepath).toLowerCase() === '.js') {
Object.assign(exports, require(filepath))
}
})
}
}
})
Contoh ini index.js file hanya auto-termasuk dalam direktori root. Hal ini dapat diperluas untuk berjalan direktori, kehormatan .gitignore, dll. Ini sudah cukup bagi saya meskipun.
Dengan file indeks di tempat, menambahkan fungsi-fungsi baru sepele.
/test/testA.js
const functions = require('firebase-functions');
exports.helloWorld = functions.https.onRequest((request, response) => {
response.send("Hello from Firebase!");
});
/test/testB.js
const functions = require('firebase-functions');
exports.helloWorld2 = functions.https.onRequest((request, response) => {
response.send("Hello again, from Firebase!");
});
npm menjalankan melayani
hasil:
λ ~/Workspace/Ventures/Author.io/Firebase/functions/ npm run serve
> functions@ serve /Users/cbutler/Workspace/Ventures/Author.io/Firebase/functions
> firebase serve --only functions
=== Serving from '/Users/cbutler/Workspace/Ventures/Author.io/Firebase'...
i functions: Preparing to emulate functions.
Warning: You're using Node.js v9.3.0 but Google Cloud Functions only supports v6.11.5.
✔ functions: helloWorld: http://localhost:5000/authorio-ecorventures/us-central1/helloWorld
✔ functions: helloWorld2: http://localhost:5000/authorio-ecorventures/us-central1/helloWorld2
Alur kerja ini cukup banyak hanya "menulis dan menjalankan", tanpa harus memodifikasi index.js file setiap kali fungsi baru/file yang akan ditambahkan/diubah/dihapus.
Saya menghabiskan banyak waktu mencari yang sama, dan di sana adalah apa yang saya pikir adalah cara terbaik untuk mencapai itu (saya'm menggunakan [email protected]):
https://codeburst.io/organizing-your-firebase-cloud-functions-67dc17b3b0da
Tidak ada keringat ;)