web-dev-qa-db-fra.com

Comment importer Firebase uniquement sur le client dans Sapper?

J'importe Firebase dans mon application Sapper, je ne veux pas que les importations soient évaluées sur le serveur. Comment puis-je m'assurer que les importations se font uniquement du côté client?

J'utilise Sapper pour exécuter sapper export Qui génère les fichiers statiques. J'ai essayé:

  • Création de l'instance Firebase dans son propre fichier et exportation des modules firebase.auth() et firebase.firestore().

  • Essayer d'ajuster le rollup.config.js pour résoudre les dépendances différemment, comme suggéré dans le message d'erreur ci-dessous. Cela apporte plus de maux de tête.

  • Création de l'instance Firebase dans client.js. Infructueux.

  • Création de l'instance dans stores.js. Infructueux.

  • Déclarer la variable et l'assigner dans onMount(). Cela m'oblige à travailler dans différentes étendues de bloc. Et se sent un peu hacky.

L'initialisation de l'application fonctionne bien:

import firebase from 'firebase/app'

const config = {...}

firebase.initializeApp(config);

J'ai également découvert que si je change l'importation juste en import firebase from 'firebase' Je n'obtiens pas cette erreur de serveur:

 @firebase/app:
Warning: This is a browser-targeted Firebase bundle but it appears it is being run in a Node environment.  If running in a Node environment, make sure you are using the bundle specified by the "main" field in package.json.

If you are using Webpack, you can specify "main" as the first item in
"resolve.mainFields": https://webpack.js.org/configuration/resolve/#resolvemainfields

If using Rollup, use the rollup-plugin-node-resolve plugin and set "module" to false and "main" to true: https://github.com/rollup/rollup-plugin-node-resolve

Je m'attendais à exporter ces fonctionnalités Firebase à partir d'un fichier et à les importer dans mes composants comme:

<script>
  import { auth } from "../firebase";
</script>

Mais dès que cette importation est incluse, le serveur de développement se bloque. Je ne veux pas l'utiliser sur le serveur, car je ne fais que générer les fichiers statiques.

Quelqu'un a-t-il des idées sur la façon de réaliser l'importation uniquement côté client?

11
Eckhardt

J'ai donc passé trop de temps là-dessus. Il n'y a pas vraiment de solution plus élégante qu'onMOunt.

Cependant, j'ai réalisé que le sapeur devrait vraiment être utilisé pour ses capacités SSR. Et j'ai écrit un article sur la configuration de Firebase avec Sapper SSR et Cloud Functions:

https://dev.to/eckhardtd/how-to-Host-a-sapper-js-ssr-app-on-firebase-hmb

Une autre solution à la question d'origine est de placer les CDN Firebase dans la portée globale via le src/template.html fichier.

<body>
    <!-- The application will be rendered inside this element,
         because `app/client.js` references it -->
    <div id='sapper'>%sapper.html%</div>

    <!-- Sapper creates a <script> tag containing `app/client.js`
         and anything else it needs to hydrate the app and
         initialise the router -->
    %sapper.scripts%
      <!-- Insert these scripts at the bottom of the HTML, but before you use any Firebase services -->

  <!-- Firebase App (the core Firebase SDK) is always required and must be listed first -->
  <script src="https://www.gstatic.com/firebasejs/6.0.4/firebase-app.js"></script>

  <!-- Add Firebase products that you want to use -->
  <script src="https://www.gstatic.com/firebasejs/6.0.4/firebase-auth.js"></script>
  <script src="https://www.gstatic.com/firebasejs/6.0.4/firebase-firestore.js"></script>
</body>
</html>

et dans le composant:

<script>
import { onMount } from 'svelte';
let database, authentication;

onMount(() => {
  database = firebase.firestore();
  authentication = firebase.auth();
});

const authHandler = () => {
  if (process.browser) {
    authentication
    .createUserWithEmailAndPassword()
    .catch(e => console.error(e));
  }
}
</script>

<button on:click={authHandler}>Sign up</button>
7
Eckhardt

J'ai pu importer Firebase en utilisant ES6. Si vous utilisez le rollup, vous devez configurer le nom namedExports dans le plugin commonjs:

//--- rollup.config.js ---
...
commonjs({
        namedExports: {
          // left-hand side can be an absolute path, a path
          // relative to the current directory, or the name
          // of a module in node_modules
          'node_modules/idb/build/idb.js': ['openDb'],
          'node_modules/firebase/dist/index.cjs.js': ['initializeApp', 'firestore'],
        },
      }),

Vous pouvez l'utiliser comme ceci:

//--- db.js ---
import * as firebase from 'firebase';
import 'firebase/database';
import { firebaseConfig } from '../config'; //<-- Firebase initialization config json

// Initialize Firebase
firebase.initializeApp(firebaseConfig);
export { firebase };
// Initialize db
export const db = firebase.firestore();

et peut-être l'utiliser dans un service comme celui-ci:

// --- userService.js ----
import { db } from './common';

const usersCol = db.collection('users');
export default {
  async login(username, password) {
    const userDoc = await usersCol.doc(username).get();
    const user = userDoc.data();
    if (user && user.password === password) {
      return user;
    }
    return null;
  },
};

MODIFIÉ Configuration de rollup complet

/* eslint-disable global-require */
import resolve from 'rollup-plugin-node-resolve';
import replace from 'rollup-plugin-replace';
import commonjs from 'rollup-plugin-commonjs';
import svelte from 'rollup-plugin-svelte';
import babel from 'rollup-plugin-babel';
import { terser } from 'rollup-plugin-terser';
import config from 'sapper/config/rollup';
import { sass } from 'svelte-preprocess-sass';
import pkg from './package.json';

const mode = process.env.NODE_ENV;
const dev = mode === 'development';
const legacy = !!process.env.SAPPER_LEGACY_BUILD;

// eslint-disable-next-line no-shadow
const onwarn = (warning, onwarn) =>
  (warning.code === 'CIRCULAR_DEPENDENCY' && warning.message.includes('/@sapper/')) || onwarn(warning);

export default {
  client: {
    input: config.client.input(),
    output: config.client.output(),
    plugins: [
      replace({
        'process.browser': true,
        'process.env.NODE_ENV': JSON.stringify(mode),
      }),
      svelte({
        dev,
        hydratable: true,
        emitCss: true,
        preprocess: {
          style: sass(),
        },
      }),
      resolve({
        browser: true,
      }),
      commonjs({
        namedExports: {
          // left-hand side can be an absolute path, a path
          // relative to the current directory, or the name
          // of a module in node_modules
          'node_modules/idb/build/idb.js': ['openDb'],
          'node_modules/firebase/dist/index.cjs.js': ['initializeApp', 'firestore'],
        },
      }),

      legacy &&
        babel({
          extensions: ['.js', '.mjs', '.html', '.svelte'],
          runtimeHelpers: true,
          exclude: ['node_modules/@babel/**'],
          presets: [
            [
              '@babel/preset-env',
              {
                targets: '> 0.25%, not dead',
              },
            ],
          ],
          plugins: [
            '@babel/plugin-syntax-dynamic-import',
            [
              '@babel/plugin-transform-runtime',
              {
                useESModules: true,
              },
            ],
          ],
        }),

      !dev &&
        terser({
          module: true,
        }),
    ],

    onwarn,
  },

  server: {
    input: config.server.input(),
    output: config.server.output(),
    plugins: [
      replace({
        'process.browser': false,
        'process.env.NODE_ENV': JSON.stringify(mode),
      }),
      svelte({
        generate: 'ssr',
        dev,
      }),
      resolve(),
      commonjs(),
    ],
    external: Object.keys(pkg.dependencies).concat(require('module').builtinModules || Object.keys(process.binding('natives'))),

    onwarn,
  },

  serviceworker: {
    input: config.serviceworker.input(),
    output: config.serviceworker.output(),
    plugins: [
      resolve(),
      replace({
        'process.browser': true,
        'process.env.NODE_ENV': JSON.stringify(mode),
      }),
      commonjs(),
      !dev && terser(),
    ],

    onwarn,
  },
};

4
Tiago Nobrega