From c6030bd2bf164c1b60ac25fd79ae30fd51720fb9 Mon Sep 17 00:00:00 2001 From: Abraham Williams <4braham@gmail.com> Date: Sun, 5 Dec 2021 16:39:35 -0600 Subject: [PATCH] Server Firestore from emulator --- .github/workflows/main.yaml | 2 +- .prettierignore | 1 + data/seed/auth_export/accounts.json | 1 + data/seed/auth_export/config.json | 1 + data/seed/firebase-export-metadata.json | 16 ++++++++ .../firestore_export.overall_export_metadata | Bin 0 -> 15 bytes data/seed/storage_export/buckets.json | 7 ++++ package.json | 7 +++- scripts/firebase-config.ts | 11 +++++- scripts/firestore-init/index.ts | 31 --------------- scripts/import.ts | 37 ++++++++++++++++++ scripts/validate-seed.sh | 3 ++ src/firebase.ts | 22 +++++++++-- 13 files changed, 99 insertions(+), 40 deletions(-) create mode 100644 data/seed/auth_export/accounts.json create mode 100644 data/seed/auth_export/config.json create mode 100644 data/seed/firebase-export-metadata.json create mode 100644 data/seed/firestore_export/firestore_export.overall_export_metadata create mode 100644 data/seed/storage_export/buckets.json delete mode 100644 scripts/firestore-init/index.ts create mode 100644 scripts/import.ts create mode 100755 scripts/validate-seed.sh diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml index b7b4f6273c..6629aa6259 100644 --- a/.github/workflows/main.yaml +++ b/.github/workflows/main.yaml @@ -9,7 +9,7 @@ jobs: strategy: fail-fast: false matrix: - script-name: [lint, test, build, types] + script-name: [lint, test, build, types, seed] steps: - name: Checkout the repo diff --git a/.prettierignore b/.prettierignore index 320c107b3e..690a54152d 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1,3 +1,4 @@ node_modules/ dist/ package-lock.json +data/seed diff --git a/data/seed/auth_export/accounts.json b/data/seed/auth_export/accounts.json new file mode 100644 index 0000000000..135e08db67 --- /dev/null +++ b/data/seed/auth_export/accounts.json @@ -0,0 +1 @@ +{"kind":"identitytoolkit#DownloadAccountResponse","users":[]} \ No newline at end of file diff --git a/data/seed/auth_export/config.json b/data/seed/auth_export/config.json new file mode 100644 index 0000000000..bb253cf776 --- /dev/null +++ b/data/seed/auth_export/config.json @@ -0,0 +1 @@ +{"signIn":{"allowDuplicateEmails":false},"usageMode":"DEFAULT"} \ No newline at end of file diff --git a/data/seed/firebase-export-metadata.json b/data/seed/firebase-export-metadata.json new file mode 100644 index 0000000000..59e430ad5b --- /dev/null +++ b/data/seed/firebase-export-metadata.json @@ -0,0 +1,16 @@ +{ + "version": "9.23.0", + "firestore": { + "version": "1.13.1", + "path": "firestore_export", + "metadata_file": "firestore_export/firestore_export.overall_export_metadata" + }, + "auth": { + "version": "9.23.0", + "path": "auth_export" + }, + "storage": { + "version": "9.23.0", + "path": "storage_export" + } +} \ No newline at end of file diff --git a/data/seed/firestore_export/firestore_export.overall_export_metadata b/data/seed/firestore_export/firestore_export.overall_export_metadata new file mode 100644 index 0000000000000000000000000000000000000000..92b92aaa7c21905cf8c4bc162fbc492e4751a2c1 GIT binary patch literal 15 Wcmdmy>*B}Az-Y{>t>MhTzz6^wj{=DR literal 0 HcmV?d00001 diff --git a/data/seed/storage_export/buckets.json b/data/seed/storage_export/buckets.json new file mode 100644 index 0000000000..f42ae4d710 --- /dev/null +++ b/data/seed/storage_export/buckets.json @@ -0,0 +1,7 @@ +{ + "buckets": [ + { + "id": "default-bucket" + } + ] +} \ No newline at end of file diff --git a/package.json b/package.json index d14392da9e..d4ed1dc70f 100644 --- a/package.json +++ b/package.json @@ -11,8 +11,10 @@ "build": "npm run clean && NODE_ENV=production rollup --config rollup.config.js", "clean": "rimraf dist", "deploy": "npm run build && NODE_ENV=production firebase deploy", + "emulators:export": "firebase emulators:export ./data/seed", + "emulators:import": "FIRESTORE_EMULATOR_HOST=\"localhost:8080\" ts-node-script ./scripts/import", "firestore:copy": "ts-node-script ./scripts/firestore-copy", - "firestore:init": "ts-node-script ./scripts/firestore-init", + "firestore:init": "ts-node-script ./scripts/import", "fix": "concurrently npm:fix:*", "fix:eslint": "eslint . --ext .ts --ext .js --fix", "fix:prettier": "prettier . --write", @@ -23,9 +25,10 @@ "lint:prettier": "prettier --check .", "lint:stylelint": "stylelint \"src/components/**/*.ts\" \"src/styles/**/*.ts\"", "postinstall": "npm run install:functions", + "seed": "firebase emulators:exec \"./scripts/validate-seed.sh\"", "serve": "NODE_ENV=production concurrently --kill-others npm:start:*", "start": "NODE_ENV=development concurrently --kill-others npm:start:*", - "start:emulators": "firebase emulators:start", + "start:emulators": "firebase emulators:start --import data/seed", "start:functions": "npm --prefix functions start", "start:rollup": "rollup --config rollup.config.js --watch", "test": "jest", diff --git a/scripts/firebase-config.ts b/scripts/firebase-config.ts index f6ff510123..80c4f08345 100644 --- a/scripts/firebase-config.ts +++ b/scripts/firebase-config.ts @@ -6,8 +6,15 @@ import { cert, initializeApp, ServiceAccount } from 'firebase-admin/app'; import { getFirestore } from 'firebase-admin/firestore'; import serviceAccount from '../serviceAccount.json'; -const credential = cert(serviceAccount as ServiceAccount); -initializeApp({ credential }); +const { FIRESTORE_EMULATOR_HOST } = process.env; + +if (FIRESTORE_EMULATOR_HOST) { + initializeApp({ projectId: 'demo-hoverboard' }); +} else { + const credential = cert(serviceAccount as ServiceAccount); + initializeApp({ credential }); +} + const firestore = getFirestore(); export { firestore }; diff --git a/scripts/firestore-init/index.ts b/scripts/firestore-init/index.ts deleted file mode 100644 index a9d925ea62..0000000000 --- a/scripts/firestore-init/index.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { importBlog } from './blog'; -import { importConfig } from './config'; -import { importGallery } from './gallery'; -import { importPartners } from './partners'; -import { importPreviousSpeakers } from './previous-speakers'; -import { importSchedule } from './schedule'; -import { importSessions } from './sessions'; -import { importSpeakers } from './speakers'; -import { importTeam } from './team'; -import { importTickets } from './tickets'; -import { importVideos } from './videos'; - -importConfig() // Should always be first - .then(() => importBlog()) - .then(() => importGallery()) - .then(() => importPartners()) - .then(() => importPreviousSpeakers()) - .then(() => importSchedule()) - .then(() => importSessions()) - .then(() => importSpeakers()) - .then(() => importTeam()) - .then(() => importTickets()) - .then(() => importVideos()) - .then(() => { - console.log('Finished'); - process.exit(); - }) - .catch((err: Error) => { - console.log(err); - process.exit(); - }); diff --git a/scripts/import.ts b/scripts/import.ts new file mode 100644 index 0000000000..cf7a7cfad9 --- /dev/null +++ b/scripts/import.ts @@ -0,0 +1,37 @@ +/** + * Execute this script to import `default-firebase-data.json` data into Firestore. + */ + +import { importBlog } from './firestore-init/blog'; +import { importConfig } from './firestore-init/config'; +import { importGallery } from './firestore-init/gallery'; +import { importPartners } from './firestore-init/partners'; +import { importPreviousSpeakers } from './firestore-init/previous-speakers'; +import { importSchedule } from './firestore-init/schedule'; +import { importSessions } from './firestore-init/sessions'; +import { importSpeakers } from './firestore-init/speakers'; +import { importTeam } from './firestore-init/team'; +import { importTickets } from './firestore-init/tickets'; +import { importVideos } from './firestore-init/videos'; + +console.log('Importing default data to Firestore'); + +importConfig() + .then(() => importBlog()) + .then(() => importGallery()) + .then(() => importPartners()) + .then(() => importPreviousSpeakers()) + .then(() => importSchedule()) + .then(() => importSessions()) + .then(() => importSpeakers()) + .then(() => importTeam()) + .then(() => importTickets()) + .then(() => importVideos()) + .then(() => { + console.log('Finished'); + process.exit(); + }) + .catch((err: Error) => { + console.log(err); + process.exit(); + }); diff --git a/scripts/validate-seed.sh b/scripts/validate-seed.sh new file mode 100755 index 0000000000..9cd8e61bce --- /dev/null +++ b/scripts/validate-seed.sh @@ -0,0 +1,3 @@ +npm run emulators:import +npm run emulators:export -- --force +test -z "$(git diff --exit-code)" diff --git a/src/firebase.ts b/src/firebase.ts index 02a2a840bd..861fa5ac31 100644 --- a/src/firebase.ts +++ b/src/firebase.ts @@ -1,10 +1,24 @@ -import { initializeApp } from 'firebase/app'; -import { getFirestore, enableMultiTabIndexedDbPersistence } from 'firebase/firestore'; +import { FirebaseApp, FirebaseOptions, initializeApp } from 'firebase/app'; +import { + connectFirestoreEmulator, + enableMultiTabIndexedDbPersistence, + getFirestore, +} from 'firebase/firestore'; import { initializePerformance } from 'firebase/performance'; +import { isLocalhost } from './utils/environment'; const response = await fetch('/__/firebase/init.json'); -export const firebaseApp = initializeApp(await response.json()); -export const db = getFirestore(firebaseApp); +const options: FirebaseOptions = await response.json(); + +const firebaseApp: FirebaseApp = initializeApp(options); +const db = getFirestore(firebaseApp); + +if (isLocalhost()) { + console.log('Connecting to Firestore Emulator'); + connectFirestoreEmulator(db, 'localhost', 8080); +} initializePerformance(firebaseApp); enableMultiTabIndexedDbPersistence(db); + +export { db, firebaseApp };