I'm received error with gatsby develop. It's very similar to this one: https://github.com/firebase/firebase-js-sdk/issues/2222, but I'm received error with gatsby develop, not with gatsby build. I did a lot of research but I can't find working solution.
At first I had a problem with gatsby build, like in this post: https://github.com/firebase/firebase-js-sdk/issues/2222, but I resolved it with custom onCreateWebpackConfig(you can find it below).
Stack:
- Gatsby
- Firebase(error probably with that)
- Redux
I'm also delete .cache and node_modules and install everything again, but it didn't work.
Error:
There was an error compiling the html.js component for the development server.
See our docs page on debugging HTML builds for help https://gatsby.dev/debug-html ReferenceError: IDBIndex is not defined
]);
86 |
> 87 | proxyRequestMethods(Index, '_index', IDBIndex, [
| ^
88 | 'get',
89 | 'getKey',
90 | 'getAll',
WebpackError: ReferenceError: IDBIndex is not defined
- idb.mjs:87 Module../node_modules/idb/lib/idb.mjs
node_modules/idb/lib/idb.mjs:87:1
- index.esm.js:1 Module../node_modules/#firebase/installations/dist/index.esm.js
node_modules/#firebase/installations/dist/index.esm.js:1:1
- index.esm.js:1 Module../node_modules/#firebase/analytics/dist/index.esm.js
node_modules/#firebase/analytics/dist/index.esm.js:1:1
- index.esm.js:1 Module../node_modules/firebase/analytics/dist/index.esm.js
node_modules/firebase/analytics/dist/index.esm.js:1:1
- index.ts:1 Module../src/firebase/index.ts
src/firebase/index.ts:1:1
- index.esm.js:32 emit
node_modules/#firebase/analytics/dist/index.esm.js:32:1
My gatsby-node file:
exports.onCreateWebpackConfig = ({ stage, actions, getConfig }) => {
if (stage === 'build-html') {
actions.setWebpackConfig({
externals: getConfig().externals.concat(function(context, request, callback) {
const regex = /^#?firebase(\/(.+))?/;
if (regex.test(request)) {
return callback(null, `umd ${request}`);
}
callback();
}),
});
}
};
My firebase dependencies:
"#firebase/firestore-types": "^1.10.1",
"firebase": "^7.13.1",
"firebase-admin": "^8.10.0",
"firebase-functions": "^3.5.0",
"firebase-tools": "^7.16.1",
Firebase index file:
import firebase from 'firebase/app';
import 'firebase/firestore';
import 'firebase/auth';
import 'firebase/storage';
import 'firebase/analytics';
const firebaseConfig = {...};
firebase.initializeApp(firebaseConfig);
export const firestore = firebase.firestore();
export const auth = firebase.auth();
export const storage = firebase.storage();
Project repo: https://github.com/olafsulich/Projecty
Post on Github issues: https://github.com/firebase/firebase-js-sdk/issues/2946
Thanks in advance.
The following snippet will only work on build environment because of your condition (stage === 'build-html'):
exports.onCreateWebpackConfig = ({ stage, actions, getConfig }) => {
if (stage === 'build-html') {
actions.setWebpackConfig({
externals: getConfig().externals.concat(function(context, request, callback) {
const regex = /^#?firebase(\/(.+))?/;
if (regex.test(request)) {
return callback(null, `umd ${request}`);
}
callback();
}),
});
}
};
Remove it and use it like this:
exports.onCreateWebpackConfig = ({ stage, actions, getConfig }) => {
actions.setWebpackConfig({
externals: getConfig().externals.concat(function(context, request, callback) {
const regex = /^#?firebase(\/(.+))?/;
if (regex.test(request)) {
return callback(null, `umd ${request}`);
}
callback();
}),
});
};
Thank's a lot! It's working only on gatbsy develop, but now when I
want to build project, I get an error - TypeError: Cannot read
property 'concat' of undefined. You know how to solve it?
Regarding the new issue, you can follow a workaround in this topic, This is a common error in third-party modules in Gatsby when they try to reach a DOM element (usually window) that is not already defined when the app builds. So, you need to wait until window is defined. You can achieve this in two ways:
Instancing your firebase with a condition like this:
import firebase from '#firebase/app';
import '#firebase/auth';
import '#firebase/firestore';
import '#firebase/functions';
const config = {
... firebase config here
};
let instance;
export default function getFirebase() {
if (typeof window !== 'undefined') {
if (instance) return instance;
instance = firebase.initializeApp(config);
return instance;
}
return null;
}
Note the if (typeof window !== 'undefined') statement
By ignoring firebase module in you webpack configuration like shows their docs. In your gatsby-node.js:
exports.onCreateWebpackConfig = ({ stage, loaders, actions }) => {
if (stage === "build-html") {
actions.setWebpackConfig({
module: {
rules: [
{
test: /bad-module/,
use: loaders.null(),
},
],
},
})
}
}
Replace bad module for firebase (or the package/folder name in node_modules). Leave the slashes since test is a regular expression rule
This snippet replaces your previous one that seems to throw an error in concat() function.
For those who wants to try the concat() resolution, this will be helpful too:
exports.onCreateWebpackConfig = ({ stage, actions, getConfig }) => {
if (stage === 'build-html') {
actions.setWebpackConfig({
externals: getConfig().externals.concat((context, request, callback) => {
const regex = /^#?firebase(\/(.+))?/
// exclude firebase products from being bundled, so they will be loaded using require() at runtime.
if (regex.test(request)) {
return callback(null, `commonjs ${request}`) // <- use commonjs!
}
callback()
}),
})
}
}
Solved this problem!!
I'm using "gatsby": "^3.10.2", "firebase": "9.0.0-beta.6".
firebase needs to be set externals as commonjs.
gatsby-node.js:
exports.onCreateWebpackConfig = ({ stage, actions, getConfig }) => {
if (stage === 'build-html') {
actions.setWebpackConfig({
externals: getConfig().externals.concat((context, request, callback) => {
const regex = /^#?firebase(\/(.+))?/
// exclude firebase products from being bundled, so they will be loaded using require() at runtime.
if (regex.test(request)) {
return callback(null, `commonjs ${request}`) // <- use commonjs!
}
callback()
}),
})
}
}
Please try this setting.
Related
I am trying to add retry functionality to defineAsyncComponent so I created a helper function
const MAX_TRY = 3;
const WAIT_TIME = 1000;
async function loadAsyncComponent(componentPath: string, tryCount = 1) {
if (tryCount > MAX_TRY) return Promise.reject();
return new Promise((resolve, reject) => {
const path = componentPath.replace('.vue', '').replace('#/modules/', '');
// https://github.com/rollup/plugins/tree/master/packages/dynamic-import-vars#limitations
import(`../../../modules/${path}.vue`).then(resolve).catch((error) => {
console.error('loading async component failed : ', error);
captureException(error);
wait(WAIT_TIME).then(() => {
loadAsyncComponent(componentPath, ++tryCount)
.then(resolve)
.catch(reject);
});
});
});
}
export default function customAsyncComponent<T>(componentPath: string): T {
return defineAsyncComponent({
// the loader function
loader: () => loadAsyncComponent(componentPath) as any,
// A component to use while the async component is loading
loadingComponent: Loading,
// Delay before showing the loading component. Default: 200ms.
delay: 200,
// A component to use if the load fails
errorComponent: AsyncLoadFailed,
// The error component will be displayed if a timeout is
// provided and exceeded. Default: Infinity.
timeout: 10000,
});
}
This works in local DEV environment but when I build and deployed to prod it broke Error: Unknown variable dynamic import: ../../../modules/room/components/room/Room.vue
It seems that these dynamic imports are not included in the final build.
Found this answer https://stackoverflow.com/a/72479802/1055015
Tryied these
rollupOptions: {
external: [path.resolve(__dirname, 'src/modules/room/components/room/Room.vue')],
},
rollupOptions: {
external: ['#/modules/room/components/room/Room.vue')],
},
After vite build The dynamically imported files are not generated in the dist folder
Any ideas ?
UPDATE: I found a workaround using glob-import testing it now
Solution 2:
The first solution left me with hundred's of small files , every single vue,ts,css file loading separately (~175),
I needed to preload them for better UX but and it started making 429 errors (too many request) on my server
So I made some changes on my custom loader and manually listed the files that needed to be preloaded
const PRELOAD_LIST = [
() => import('#/modules/X.vue'),
];
async function loadAsyncComponent(componentLoader: any, tryCount = 1) {
return new Promise((resolve, reject) => {
componentLoader() // <--------------- this part mostly
.then(resolve)
.catch((error) => {
console.error('loading async component failed : ', error);
captureException(error);
if (tryCount >= MAX_TRY) reject(error);
else {
wait(WAIT_TIME).then(() => {
loadAsyncComponent(componentLoader, ++tryCount)
.then(resolve)
.catch(reject);
});
}
});
});
}
const X = customAsyncComponent(() => import('#/modules/X.vue'));
Solution 1:
For now I used this approach :
const MODULES = import.meta.glob('../../../modules/**/*.vue');
this generates a key/value object list, the keys are the file path's and the values are import statements with static path
// code produced by vite
const MODULES = {
'../../../modules/dir/foo.vue': () => import('./modules/dir/foo.vue'),
'../../../modules/dir/bar.vue': () => import('./modules/dir/bar.vue')
}
Then you can just do MODULES[myPath]() to load the file/module.
This works but it also generates extra code for the modules at I don't really need to, so I am still looking for a better solution.
How to access boot file configured axios from Quasar V2 Composition API setup function, without importing axios in every file?
Since this.$axios can be used only for Options API, I tried to access through the context parameter of setup function.
Even though it works, context.root is now deprecated in Vue 3.
I do not want to import axios in every file as shown in the example at https://next.quasar.dev/quasar-cli/ajax-requests
For setup method access, I think it is still not implemented since mentioned as a TODO activity at https://next.quasar.dev/quasar-cli/boot-files#examples-of-appropriate-usage-of-boot-files
Similar to axios, usage of vue-i18n also from boot file is an issue for me.
setup (props, context) {
context.root.$axios({
method: 'get',
url: 'http://localhost:8080/storemgr/item/3',
}).then((response: any) => {
console.log(response)
}).catch((error: any) => {
console.log(error)
})
...
}
Below is my axios boot file contents generated by Quasar V2 CLI
import axios, { AxiosInstance } from 'axios'
import { boot } from 'quasar/wrappers'
declare module 'vue/types/vue' {
interface Vue {
$axios: AxiosInstance;
}
}
export default boot(({ Vue }) => {
// eslint-disable-next-line #typescript-eslint/no-unsafe-member-access
Vue.prototype.$axios = axios
})
The only other way I found is to use Provide/Inject.
In my boot file, I use it like this:
export default boot(({ app }) => {
app.config.globalProperties.$axios = axios
app.provide('axios', app.config.globalProperties.$axios)
})
In any component:
setup() {
const axios: AxiosInstance = inject('axios') as AxiosInstance
[...]
}
In hindsight, I'm not quite sure if this is better than importing it.
For This worked
import {api} from 'boot/axios'
setup() {
return{
api.post('shop/', data, { #api imported that works in setup quasar
headers: {
Authorization: `token ${JSON.parse(localStorage.getItem("userData")).token}`,
'Content-Type': 'multipart/form-data'
},
onUploadProgress: function (progressEvent) {
console.log((progressEvent.loaded / progressEvent.total) * 100);
dialog.update({
message: `${(progressEvent.loaded / progressEvent.total) * 100}%`
})
}
})
}
}
I am trying to write jest tests using the Firebase Auth emulator and continue to receive the following CORS error.
console.error
Error: Headers X-Client-Version forbidden
at dispatchError (/Users/me/my-project/node_modules/jsdom/lib/jsdom/living/xhr/xhr-utils.js:62:19)
at validCORSPreflightHeaders (/Users/me/my-project/node_modules/jsdom/lib/jsdom/living/xhr/xhr-utils.js:99:5)
at Request.<anonymous> (/Users/me/my-project/node_modules/jsdom/lib/jsdom/living/xhr/xhr-utils.js:367:12)
at Request.emit (events.js:315:20)
at Request.onRequestResponse (/Users/me/my-project/node_modules/request/request.js:1059:10)
at ClientRequest.emit (events.js:315:20)
at HTTPParser.parserOnIncomingClient [as onIncoming] (_http_client.js:641:27)
at HTTPParser.parserOnHeadersComplete (_http_common.js:126:17)
at Socket.socketOnData (_http_client.js:509:22)
at Socket.emit (events.js:315:20) undefined
The test is very simple:
import { renderHook, act } from "#testing-library/react-hooks"
import faker from "faker"
import { useAuth, FirebaseProvider, firebase } from "./index"
const wrapper = ({ firebase, children }) => {
return <FirebaseProvider firebase={firebase}>{children}</FirebaseProvider>
}
const createUser = ({ email = faker.internet.email(), password = faker.internet.password({ length: 6 }) } = {}) => {
return firebase
.auth()
.createUserWithEmailAndPassword(email, password)
.then(user => user)
}
const signUserIn = ({ email, password } = {}) => {
return firebase
.auth()
.signInWithEmailAndPassword(email, password)
.then(user => user)
}
describe("useAuth", () => {
it("will return the user", async () => {
const { result } = renderHook(() => useAuth(), { wrapper, initialProps: { firebase } })
const email = faker.internet.email()
const password = faker.internet.password()
await act(async () => {
const user = await createUser({ email, password }) // this fails
await signUserIn({ email, password }) //and so does this
})
expect(result.user).toEqual({ email, password })
})
})
And for reference, the index file:
const FirebaseProvider = ({ children, firebase }) => {
const firestore = firebase.firestore()
const auth = firebase.auth()
if (useEmulator()) {
firestore.useEmulator("localhost", 8080)
auth.useEmulator("http://localhost:9099/")
}
const value = { firestore, auth }
return <FirebaseContext.Provider value={value}>{children}</FirebaseContext.Provider>
}
const throwError = hook => {
throw new Error(`${hook} must be used within a FirebaseProvider`)
}
const useAuth = () => {
const context = useContext(FirebaseContext)
if (context === undefined) throwError("useAuth")
const [user, setUser] = useState()
useEffect(() => {
const cleanup = context.auth.onAuthStateChanged(authUser => {
authUser ? setUser(authUser) : setUser(null)
})
return () => cleanup()
})
return { ...context.auth, user }
}
I have tried using the REST endpoint that the actual emulator uses (below) and it errors in the same way.
http://localhost:9099/identitytoolkit.googleapis.com/v1/projects/<my-project>/accounts
Is there anyway to get this to run when using jest? Or do I need to create the accounts using the emulator UI, export them and re-import when I am running tests?
I have found I can use the REST endpoint below to make a user in the test, however it bypasses the emulator and makes a real user.
https://identitytoolkit.googleapis.com/v1/accounts:signUp?key=<api-key>
Update jsdom version 16.5.2
This new version now supports wildcards for access-control-allow-headers, so updating to this version or using it as resolution, for projects created with Create React App, solves the problem.
Solution for jsdom prior to version 16.5.2
The error is thrown by jsdom because it doesn't support wildcard for access-control-allow-headers, but firebase uses the wildcard (see this issue for jsdom and this pull request related to firebase). There are two open pull requests to fix this issue: https://github.com/jsdom/jsdom/pull/3073 and https://github.com/jsdom/jsdom/pull/2867.
The issue can be fixed by either changing the relevant code manually in the node_modules folder or by using the fork as dependency in the package.json:
"jsdom": "silviot/jsdom#fix/allow-headers"
If jsdom isn't a direct dependency, then you can add the following to the package.json at the top level:
"resolutions": {
"jsdom": "silviot/jsdom#fix/allow-headers"
}
If the fork is used there are some auto-generated files missing in the jsdom folder. These can be generated by running npm install or yarn install in the folder. To automate this you can add a prepare script to the package.json:
"scripts": {
"prepare": "cd node_modules/jsdom && yarn"
},
I also had problems making users programaticly in the firebase auth emulator.
Instead of using
https://identitytoolkit.googleapis.com/v1/accounts:signUp?key=[API_KEY]
You have to use the following format:
http://localhost:9099/identitytoolkit.googleapis.com/v1/accounts:signUp?key=[API_KEY]
Then giving a JSON body like this, and hit post
{
"email": "test#test.com",
"password": "test12"
}
And voila! You have a user in your emulator. Combine this with fetch or axios and you seed your emulator with users. If you need to add custom claims or other info, create function in the functions emulator that triggers on user creation.
functions.auth.user().onCreate
I am implementing ngx-translate-router in an Angular Universal app that is already working in SSR but once I added this module SSR does not run anymore.
But works correctly with ng serve so it means that the integration of this module without SSR is working fine.
But when running in SSR mode : npm run serve:ssr i get this error :
NetworkError
at XMLHttpRequest.send (F:\GitaLab\vyv-angular\dist\server\main.js:1:819512)
at Observable_Observable._subscribe (F:\GitaLab\vyv-angular\dist\server\main.js:1:3285565)
at Observable_Observable._trySubscribe (F:\GitaLab\vyv-angular\dist\server\main.js:1:576303)
at Observable_Observable.subscribe (F:\GitaLab\vyv-angular\dist\server\main.js:1:576085)
at CatchOperator.call (F:\GitaLab\vyv-angular\dist\server\main.js:1:3994238)
at Observable_Observable.subscribe (F:\GitaLab\vyv-angular\dist\server\main.js:1:575939)
at DoOperator.call (F:\GitaLab\vyv-angular\dist\server\main.js:1:3343772)
at Observable_Observable.subscribe (F:\GitaLab\vyv-angular\dist\server\main.js:1:575939)
at F:\GitaLab\vyv-angular\dist\server\main.js:1:3315893
at Observable_Observable._subscribe (F:\GitaLab\vyv-angular\dist\server\main.js:1:3316238)
I implemented the SSR part based on the instructions of ngx-translate-router so what i did additional for the SSR part are the following :
1 - implemented an interceptor in the app.server.module.ts to be able to access the translations within the server part. Here is the interceptor :
import { REQUEST } from '#nguniversal/express-engine/tokens';
import * as express from 'express';
import {Inject, Injectable} from '#angular/core';
import {HttpHandler, HttpInterceptor, HttpRequest} from '#angular/common/http';
#Injectable()
export class TranslateInterceptor implements HttpInterceptor {
private readonly DEFAULT_PORT = 4200;
private readonly PORT = process.env.PORT || this.DEFAULT_PORT;
constructor(#Inject(REQUEST) private request: express.Request) {}
getBaseUrl(req: express.Request) {
const { protocol, hostname } = req;
return this.PORT ?
`${protocol}://${hostname}:${this.PORT}` :
`${protocol}://${hostname}`;
}
intercept(request: HttpRequest<any>, next: HttpHandler) {
if (request.url.startsWith('./assets')) {
const baseUrl = this.getBaseUrl(this.request);
request = request.clone({
url: `${baseUrl}/${request.url.replace('./assets', 'assets')}`
});
}
return next.handle(request);
}
}
2 - I modified the server.ts to access the different locales and added the routes for them, but I think the issues lies there. I think I incorrectly added the routes listening in the server.ts but i did not find help about this anywhere...
here is the server.ts
// The Express app is exported so that it can be used by serverless Functions.
export function app(): express.Express {
const server = express();
const distFolder = join(process.cwd(), 'dist/browser');
const fs = require('fs');
const data: any = JSON.parse(fs.readFileSync(`src/assets/locales.json`, 'utf8'));
const indexHtml = existsSync(join(distFolder, 'index.original.html')) ? 'index.original.html' : 'index';
server.use(cookieParser());
// Our Universal express-engine (found # https://github.com/angular/universal/tree/master/modules/express-engine)
server.engine('html', ngExpressEngine({
bootstrap: AppServerModule,
}));
server.set('view engine', 'html');
server.set('views', distFolder);
server.get('/', (req, res) => {
const defaultLang = 'en';
const lang = req.acceptsLanguages('en', 'de', 'fr', 'es', 'pt');
let cookieLang = req.cookies.lang;
if (!cookieLang) {
cookieLang = req.cookies.LOCALIZE_DEFAULT_LANGUAGE; // This is the default name of cookie
}
const definedLang = cookieLang || lang || defaultLang;
console.log('domain requested without language');
res.redirect(301, `/${definedLang}/`);
});
// Example Express Rest API endpoints
// server.get('/api/**', (req, res) => { });
// Serve static files from /browser
server.get('*.*', express.static(distFolder, {
maxAge: '1y'
}));
console.log('routes for the locales:');
console.log(data);
data.locales.forEach(route => {
server.get(`/${route}`, (req: express.Request, res: express.Response) => {
console.log('domain requested with language' + req.originalUrl);
res.render(indexHtml, {
req, providers: [
{ provide: REQUEST, useValue: req }
]
});
});
server.get(`/${route}/*`, (req: express.Request, res: express.Response) => {
console.log('page requested with language ' + req.originalUrl);
res.render(indexHtml, {
req, providers: [
{ provide: REQUEST, useValue: req }
]
});
});
});
return server;
}
function run(): void {
const port = process.env.PORT || 4000;
// Start up the Node server
const server = app();
server.use(compression());
server.listen(port, () => {
console.log(`Node Express server listening on http://localhost:${port}`);
});
}
// Webpack will replace 'require' with '__webpack_require__'
// '__non_webpack_require__' is a proxy to Node 'require'
// The below code is to ensure that the server is run only when not requiring the bundle.
declare const __non_webpack_require__: NodeRequire;
const mainModule = __non_webpack_require__.main;
const moduleFilename = mainModule && mainModule.filename || '';
if (moduleFilename === __filename || moduleFilename.includes('iisnode')) {
run();
}
export * from './src/main.server';
when I start the SSR server and then request the page http://localhost
I can see the redirect working to the default language and the console logs the "domain requested with language /en/" before the error reported above.
I think the issue is that the server.ts does not manage to map the requested url to something within the routes declared in the app-routing.module.ts but i don't know how to do that.
In the GitHub repository of ngx-translate-router they say :
// let node server knows about the new routes:
let fs = require('fs');
let data: any = JSON.parse(fs.readFileSync(`src/assets/locales.json`, 'utf8'));
app.get('/', ngApp);
data.locales.forEach(route => {
app.get(`/${route}`, ngApp);
app.get(`/${route}/*`, ngApp);
});
but they don't describe what "ngApp" is so i just extrapolated it base on how the server.ts was before integrating this plugin:
// All regular routes use the Universal engine
server.get('*', (req: express.Request, res: express.Response) => {
res.render(indexHtml, {
req, providers: [
{ provide: REQUEST, useValue: req }
]
});
});
So my question is double. Do you think I am right to keep searching on the direction that I dentified ? (server.ts implementation is wrong).
If yes do you have an idea how to correct it ?
If no, any other direction to look for ?
The error was not in the server.ts, but the interceptor. I originally designed this interceptor and I thought it could be shared just like that to retrieve the data from ./assets/locales.json as it was working fine in SSR for retrieving the ./assets/i18n/en.json, but no luck. ngx-translate and ngx-translate-router cannot share the same interceptor, I don't know why but that's it. So I had to create a second interceptor (code below) and this solved my issue.
import { REQUEST } from '#nguniversal/express-engine/tokens';
import * as express from 'express';
import {Inject, Injectable, PLATFORM_ID} from '#angular/core';
import {HttpHandler, HttpInterceptor, HttpRequest} from '#angular/common/http';
import {isPlatformServer} from '#angular/common';
#Injectable()
export class LocalizeInterceptor implements HttpInterceptor {
constructor(#Inject(REQUEST) private request: express.Request, #Inject(PLATFORM_ID) private platformId: any) {}
intercept(request: HttpRequest<any>, next: HttpHandler) {
if (request.url.startsWith('assets') && isPlatformServer(this.platformId)) {
const req = this.request;
const url = req.protocol + '://' + req.get('host') + '/' + request.url;
request = request.clone({
url
});
}
return next.handle(request);
}
}
I'm trying to use google sign using firebase in the Vue framework. I don't know what the error is this can anyone help me with this.
vue.runtime.esm.js?2b0e:1888 TypeError: _firebase_js__WEBPACK_IMPORTED_MODULE_2__.fb.auth.GoogleAuthProvider is not a constructor
at VueComponent.socialLogin (Signin.vue?3d55:76)
at invokeWithErrorHandling (vue.runtime.esm.js?2b0e:1854)
at HTMLButtonElement.invoker (vue.runtime.esm.js?2b0e:2179)
at HTMLButtonElement.original._wrapper (vue.runtime.esm.js?2b0e:6917)
this is my code
firebase.js
import firebase from "firebase";
var firebaseConfig = {
config
};
const fb=firebase.initializeApp(firebaseConfig);
export { fb };
Sign in.vue
<script>
import { fb } from "../firebase.js";
export default {
name: "Signin",
components: {},
data() {
return {
};
},
methods: {
socialLogin() {
const provider = new fb.auth.GoogleAuthProvider();
fb.auth().signInWithPopup(provider).then((result) => {
this.$router.replace('home');
}).catch((err) => {
alert('Oops. ' + err.message)
});
}
}
};
</script>
The auth property (not the auth() function) is available on the static firebase object, not your firebase app.
You want something more like this
import firebase from "firebase/app"
import "firebase/auth" // 👈 this could also be in your `firebase.js` file
const provider = new firebase.auth.GoogleAuthProvider()