Firebase-js-sdk: Cannot load firestore with typescript

Created on 13 Jul 2018  Â·  15Comments  Â·  Source: firebase/firebase-js-sdk


[REQUIRED] Describe your environment

  • Operating System version: Windows 10
  • Browser version: Version 67.0.3396.99 (Official Build) (64-bit)
  • Firebase SDK version: 5.1.0
  • Firebase Product: firestore

[REQUIRED] Describe the problem

I am trying to create a small module that exports my auth and firestore components. This is a typescript react mobx project. My package.json file looks like this:

{
  "name": "typescript-react-mobx-boilerplate",
  "version": "1.0.0",
  "private": true,
  "description": "A frontend boilerplate with React, MobX and Typescript",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "webpack-dev-server --mode development --hot --progress --colors --port 3000 --host 0.0.0.0 --open",
    "build": "webpack -p --progress --colors",
    "prettier": "prettier --write \"src/**/*.{ts,tsx,css}\""
  },
  "license": "MIT",
  "devDependencies": {
    "@types/classnames": "^2.2.3",
    "@types/googlemaps": "^3.30.9",
    "@types/markerclustererplus": "^2.1.33",
    "@types/node": "^9.4.6",
    "@types/react": "^16.0.40",
    "@types/react-dom": "^16.0.4",
    "@types/react-router": "^4.0.22",
    "@types/react-router-dom": "^4.2.6",
    "@types/webpack": "^3.8.8",
    "automapper-ts": "^1.9.0",
    "awesome-typescript-loader": "^5.2.0",
    "babel-loader": "^7.1.3",
    "css-loader": "^0.28.10",
    "extract-text-webpack-plugin": "^4.0.0-beta.0",
    "file-loader": "^1.1.11",
    "html-loader": "^1.0.0-alpha.0",
    "html-webpack-plugin": "^3.2.0",
    "mobx-react-devtools": "^4.2.15",
    "postcss": "^6.0.19",
    "postcss-browser-reporter": "^0.5.0",
    "postcss-cssnext": "^3.1.0",
    "postcss-import": "^11.1.0",
    "postcss-loader": "^2.1.1",
    "postcss-reporter": "^5.0.0",
    "postcss-url": "^7.3.1",
    "prettier": "^1.11.1",
    "react-hot-loader": "^4.0.0",
    "style-loader": "^0.20.2",
    "typescript": "^2.9.2",
    "url-loader": "^1.0.0-beta.0",
    "webpack": "^4.12.1",
    "webpack-cleanup-plugin": "^0.5.1",
    "webpack-cli": "^2.0.10",
    "webpack-dev-server": "^3.1.4",
    "webpack-hot-middleware": "^2.21.1"
  },
  "dependencies": {
    "classnames": "^2.2.5",
    "firebase": "^5.1.0",
    "luxbar": "^0.3.2",
    "mini-css-extract-plugin": "^0.4.1",
    "mobx": "^3.6.1",
    "mobx-react": "^4.4.2",
    "mobx-react-router": "^4.0.1",
    "npm": "^6.1.0",
    "react": "^16.2.0",
    "react-dom": "^16.2.0",
    "react-google-maps": "^9.4.5",
    "react-router": "^4.2.0",
    "react-router-dom": "^4.2.2",
    "react-toastify": "^4.1.0",
    "react-transition-group": "^1.2.1"
  }
}

and my webpack.config file looks like this:
```javascript
var webpack = require('webpack');
var path = require('path');

// variables
var isProduction = process.argv.indexOf('-p') >= 0;
var sourcePath = path.join(__dirname, './src');
var outPath = path.join(__dirname, './dist');

// plugins
var HtmlWebpackPlugin = require('html-webpack-plugin');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
var WebpackCleanupPlugin = require('webpack-cleanup-plugin');

module.exports = {
context: sourcePath,
entry: {
main: './main.tsx'
},
output: {
path: outPath,
filename: 'bundle.js',
chunkFilename: '[chunkhash].js',
publicPath: isProduction ? '/Wedding' : '/'
},
target: 'web',
resolve: {
extensions: ['.js', '.ts', '.tsx'],
// Fix webpack's default behavior to not load packages with jsnext:main module
// (jsnext:main directs not usually distributable es6 format, but es6 sources)
mainFields: ['module', 'browser', 'main'],
alias: {
app: path.resolve(__dirname, 'src/app/'),
assets: path.resolve(__dirname, 'src/assets/')
}
},
module: {
rules: [
// .ts, .tsx
{
test: /.tsx?$/,
exclude: /node_modules/,
use: [
isProduction
? 'awesome-typescript-loader'
: {
loader: 'babel-loader',
options: {
babelrc: false,
plugins: ['react-hot-loader/babel']
}
},
isProduction
? null
: {
loader: 'awesome-typescript-loader',
options: {}
}
]
},

  // css
  {
    test: /\.css$/,
    exclude: /node_modules/,
    use: ExtractTextPlugin.extract({
      fallback: 'style-loader',
      use: [
        {
          loader: 'css-loader',
          query: {
            modules: true,
            sourceMap: !isProduction,
            importLoaders: 1,
            localIdentName: '[local]__[hash:base64:5]'
          }
        },
        {
          loader: 'postcss-loader',
          options: {
            ident: 'postcss',
            plugins: [
              require('postcss-import')({ addDependencyTo: webpack }),
              require('postcss-url')(),
              require('postcss-cssnext')(),
              require('postcss-reporter')(),
              require('postcss-browser-reporter')({
                disabled: isProduction
              })
            ]
          }
        }
      ]
    })
  },
  {
    test: /\.css$/,
    include: /node_modules/,
    use: ['style-loader', 'css-loader']
  },
  // static assets
  { test: /\.html$/, use: 'html-loader' },
  { test: /\.(png|jpg|gif)$/, use: 'url-loader?limit=10000' },
  { test: /\.webm$/, use: 'file-loader' }
]

},
optimization: {
splitChunks: {
name: true,
cacheGroups: {
commons: {
chunks: 'initial',
minChunks: 2
},
vendors: {
test: /[\/]node_modules[\/]/,
chunks: 'all',
priority: -10
}
}
},
runtimeChunk: true
},
plugins: [
new WebpackCleanupPlugin(),
new ExtractTextPlugin({
filename: 'styles.css',
disable: !isProduction
}),
new HtmlWebpackPlugin({
template: 'assets/index.html'
})
],
devServer: {
contentBase: sourcePath,
hot: true,
inline: true,
historyApiFallback: {
disableDotRule: true
},
stats: 'minimal'
},
devtool: 'cheap-module-eval-source-map',
node: {
// workaround for webpack-dev-server issue
// https://github.com/webpack/webpack-dev-server/issues/60#issuecomment-103411179
fs: 'empty',
net: 'empty'
}
};

#### Steps to reproduce:

With this setup my firebase module looks like this: 

```typescript
import * as firebase from 'firebase/app';
import '@firebase/firestore';
import '@firebase/auth';

const config = {
  apiKey: '###########################',
  authDomain: '#############firebaseapp.com',
  databaseURL: 'https://#################.firebaseio.com',
  projectId: '###############'
};



export const app = = firebase.initializeApp(config);
export const auth = firebase.auth(app);
export const database = firebase.firestore(app);

This causes warnings in my loader:

WARNING in ./app/stores/FirebaseStore.tsx 17:18-31
"export 'auth' (imported as 'firebase') was not found in 'firebase/app'

WARNING in ./app/stores/FirebaseStore.tsx 18:22-40
"export 'firestore' (imported as 'firebase') was not found in 'firebase/app'

WARNING in ./app/stores/FirebaseStore.tsx 16:11-33
"export 'initializeApp' (imported as 'firebase') was not found in 'firebase/app'

And then in the console in chrome:

Uncaught TypeError: firebase_app__WEBPACK_IMPORTED_MODULE_0__.initializeApp is not a function
    at Module.eval (FirebaseStore.tsx?c599:17)
    at eval (FirebaseStore.tsx:44)
    at Module../app/stores/FirebaseStore.tsx (24fc1a265799f413611d.js:2048)
    at __webpack_require__ (bundle.js:780)
    at fn (bundle.js:148)
    at Module.eval (index.tsx:7)
    at eval (index.tsx:209)
    at Module../app/pages/Guest/Login/index.tsx (24fc1a265799f413611d.js:1265)
    at __webpack_require__ (bundle.js:780)
    at fn (bundle.js:148)

Its driving me nuts. Ive tried so many combinations to try and fix this and I just can't resolve it. What is going on? I can't seem to get typescript and firestore to play nice together. Please help!

Relevant Code:

Here is the basics of it on stackblitz.

https://stackblitz.com/edit/firebase-issue-sandbox-gtkshz

I assume its got something to do with types not being exported for firestore. I am trying to use this site for our wedding and Im so late with getting things up. Any help as soon as possible would be so helpful! I can provide any missing information otherwise. Thanks so much for anyone giving this their time.

firestore

All 15 comments

I'm not 100% sure, but I don't think the @firebase packages are meant for public usage. Perhaps just changing import '@firebase/...' to import 'firebase/...' will fix the issue?

Yeah I figured that might be the case.. but it doesn't seem to have any effect at all. I still get the same warnings :(

Not 100% sure if it'll solve your issue, but I got your stackblitz working (https://stackblitz.com/edit/firebase-issue-sandbox-hhbeye). Basically I:

  • Updated 'firebase' module to latest (5.2.0) and removed all the other firebase dependencies.
  • changed import * as firebase from 'firebase' to import firebase from 'firebase'
  • changed @firebase to firebase

Awesome. Thanks. I’ll check it out when I get back. Am away for the weekend.

Back now. @mikelehen Ive updated my firebase from 5.1 to 5.2 (didn't realize i was behind :/). Ive created a new stackblitz as I'm using typescript so import firebase from 'firebase' in this case won't work. Im still stuck as even updating my project to 5.2 and using the firebase packages sans '@' still results in the same problems :/ here the new stackblitz with typescript:

https://stackblitz.com/edit/react-ts-dvv5fy?file=index.tsx

Any ideas? What strikes me the most weird is the

WARNING in ./app/stores/FirebaseStore.ts 16:10-32 "export 'initializeApp' (imported as 'firebase') was not found in 'firebase/app'

That I get..,.. its like its not working to import them :/ I don't know why.... maybe something to do with my typescript config and not firebase??

json { "compilerOptions": { "sourceMap": true, "target": "es5", "jsx": "react", "module": "es6", "moduleResolution": "node", "emitDecoratorMetadata": true, "experimentalDecorators": true, "declaration": false, "noImplicitAny": false, "noImplicitReturns": false, "keyofStringsOnly": true, "noUnusedLocals": true, "removeComments": true, "strictNullChecks": false, "outDir": "build", "lib": ["es6", "es7", "dom"], "baseUrl": "src", "paths": { "app/*": ["./app/*"] } }, "exclude": ["dist", "build", "node_modules"] }

Looks like you missed this step:

  • changed import * as firebase from 'firebase' to import firebase from 'firebase'

It should still work like that. What error does it give when you try this?

Edit: Also, the recommended way is to do this:

import firebase from 'firebase/app';
import 'firebase/firestore';
import 'firebase/auth';

@mmermerkaya That won't compile with typescript.

Can you provide an error message?

@mmermerkaya

image

````
✖ 「atl」: Checking finished with 1 errors ✖ 「wdm」: 690 modules

ERROR in [at-loader] ./src/app/stores/FirebaseStore.ts:1:8
TS1192: Module '"C:/Development/WeddingClient/node_modules/firebase/index"' has no default export.
ℹ 「wdm」: Failed to compile.
````

You should add "esModuleInterop": true to your tsconfig.json. TypeScript team "highly recommends applying it both to new and existing projects". See TS 2.7 release notes for more information (search for "esModuleInterop", it's close to the bottom of the page).

If it still doesn't work, try changing "module": "es6" to "module": "commonjs" in your TSConfig.

@mmermerkaya Interesting. Changing the mode to commonjs seems to work! Hallelujah! This with having my imports as import * as firebase from 'firebase' still though and NOT including esModuleInterop. However if I leave my mode at es6 with mode at es6 and DO include esModuleInterop and try import to a standard import import firebase from 'firebase' I get an error

````
✖ 「atl」: Checking finished with 1 errors ✖ 「wdm」: 690 modules

ERROR in [at-loader] ./src/app/stores/FirebaseStore.ts:1:8
TS1192: Module '"C:/Development/WeddingClient/node_modules/firebase/index"' has no default export.
ℹ 「wdm」: Failed to compile.
````

So it seems the module dictates the problem here as it seems to be irrelevant of whether esModuleInterop is true or not.

Now... if I I leave module at es6 and DO include both esModuleInterop and allowSyntheticDefaultImports as true it COMPILES!

To summarize:

{ "compilerOptions": { "module": "commonjs" }} => COMPILES
{ "compilerOptions": { "module": "es6", "esModuleInterop": true, }} => FAILS
{ "compilerOptions": { "module": "es6", "esModuleInterop": true, "allowSyntheticDefaultImports": true, }} => COMPILES
{ "compilerOptions": { "module": "commonjs", "esModuleInterop": true, }} => COMPILES
{ "compilerOptions": { "module": "commonjs", "esModuleInterop": true, "allowSyntheticDefaultImports": true, }} => COMPILES

What's really frustrating is that regardless of what my .tsconfig file is set at VS Code gives me an error in the editor even though it compiles :

image

:(

I wish I understood all of this a bit better.

{ "compilerOptions": { "module": "es6", "esModuleInterop": true, }} => FAILS
{ "compilerOptions": { "module": "es6", "esModuleInterop": true, "allowSyntheticDefaultImports": true, }} => COMPILES

That is really weird, because unless you're explicitly disabling it, enabling esModuleInterop should also enable allowSyntheticDefaultImports by default. :confused: See its definition here.

AFAIK, changing module to "commonjs" delegates all module resolution to Webpack, and Webpack knows how to find and import submodules better than TypeScript.

VSCode usually needs a restart when you change TSConfig settings. I created a tiny project to test it and it seems to work on my machine.

Also you should import firebase from 'firebase/app', not from 'firebase' :slightly_smiling_face:

@mmermerkaya Yeah, a lot of this stuff is over my head. However seeing as how things are playing nicely with the current typescript syntax import * as A from 'A', i think ill just go with the "mode": "commonjs" route for the moment. Ill have to spend some time reading up on the compilerOptions a bit more when I have time. Thank you so much for your help.

Also you should import firebase from 'firebase/app', not from 'firebase' 🙂

Definitely :)

With all these tools and compilers and bundlers, it's hard to figure out what does what. And TypeScript definitely has too many compiler options. :smile:

No problem, glad I could help. :slightly_smiling_face:

{ "compilerOptions": { "module": "es6", "esModuleInterop": true, "allowSyntheticDefaultImports": true, }}
And a vscode reset fixed my problem.

Before that I couldn't get auth and firestore to load onto firebase.* . I could get firebase.auth and firebase.initializeApp with import * as firebase from 'firebase/app' but I couldn't get firebase.firestore() no matter what I imported from '@firebase' or 'firebase', which btw is pretty confusing.

Really need some better docs on how to import in different situations, a typescript section in the firebase docs would help a ton of people.

Was this page helpful?
0 / 5 - 0 ratings