web-dev-qa-db-fra.com

passer les variables d'environnement pendant la phase de construction de babel pour importer différents fichiers

Je construis un site Web (react avec webpack & babel) et des applications mobiles (react-native avec expo) pour un projet. J'ai donc créé une bibliothèque commune pour la logique métier et la bibliothèque redux/api.

Certains codes seront légèrement différents entre Web et mobile. Dans mon cas, c’est localStorage vs AsyncStorage, que j’utilise entre autres pour s’authentifier ...

J'essaie de transmettre une variable d'environnement pour la phase de construction afin de passer de l'importation de certains fichiers de sorte que le fichier correct chargé pour chaque construction soit simplement lié à un chemin (c'est-à-dire, aucune faire import '../mylib') ex: 

if(PLATFORM === 'mobile'){
   import StorageModule from './mobile-storage-module`
} else {
   import StorageModule from './mobile-storage-module`
}
export default StorageModule

Essayez 1

@babel/preset-env pour indiquer si c'est mobile ou sur le Web, de sorte qu'il importe différentes bibliothèques en fonction de la construction, comme ceci: 

Mon .babelrc a ceci: 

{
  "presets": [
    [
      "@babel/preset-env",
      {
        "platform": "mobile"
      }
    ]
  ]
}

Et puis dans le fichier de stockage local, je fais ceci: 

export default () => {
    const platform = process.env.platform
    if (platform === 'mobile') {
        return import './storage-modules/storage-mobile'
    }
    return import './storage-modules/storage-web'
}

Cela n'a pas fonctionné, et cela n'a pas fonctionné non plus pour moi.

Essayez 2

J'ai installé react-native-dotenv et créé un fichier .env avec: PLATFORM=mobile Et mettre le plugin dans mon .babelrc

{
  "presets": [
    "babel-preset-expo",
    "react-native-dotenv"
  ]
}

Et dans mon exemple de fichier, j'ai essayé ceci: 

import { PLATFORM } from 'react-native-dotenv'
export default PLATFORM === 'mobile' ? import './storage-modules/storage-mobile' : import './storage-modules/storage-web'

Mais maintenant, ma construction ne fonctionne pas. Avez-vous une idée de la manière dont je fais des importations dynamiques pendant le processus de construction qui fonctionne pour babel dans la version de l'application respons-native et de la compilation WebPack (utilise également Babel)? 

10
denislexic

Tout d'abord, @babel/preset-env ne fait pas ce que vous pensez qu'il fait. Ce n'est pas pour spécifier vos propres variables, c'est un plugin pour utiliser automatiquement la bonne cible et pollyfills pour les navigateurs que vous voulez supporter.

Le moyen le plus simple d’obtenir des variables d’environnement est d’utiliser le plugin webpack define (qui fait partie de webpack, il n’est donc pas nécessaire d’installer quoi que ce soit d’autre).

Ajoutez simplement ceci à votre config webpack.

plugins: [
    new webpack.DefinePlugin({
        'process.env': {
            platform: 'mobile',
        },
    }),
],

Ensuite, vous ne pouvez pas utiliser les instructions import normales dans ifs .import est résolu avant l’exécution du code, que ce soit lors de la génération par Webpack ou dans des environnements pris en charge lors du chargement de script . utiliser les importations dynamiques.

Voici un exemple de ce à quoi cela pourrait ressembler.

export default new Promise(async resolve => {
    resolve(
        process.env.platform === 'mobile'
            ? (await import('./mobile.js')).default
            : (await import('./desktop.js')).default
    );
});

Vous pouvez maintenant importer à partir de ce fichier comme vous le feriez normalement, mais sachez que l'exportation par défaut est une promesse. 

2
lukas-reineke

Comme le titre de votre question indique "au cours de la phase de construction de Babel", je suppose que vous souhaitez créer différentes versions pour les ordinateurs de bureau et les appareils mobiles (pas une seule pour les deux et charger dynamiquement les modules nécessaires). Donc j'irais comme ceci:

Définissez les scripts d'exécution dans package.json pour les ordinateurs de bureau et mobiles:

"scripts": {
  "devmobile": "cross-env NODE_ENV=development PLATFORM=mobile webpack --progress",
  "dev": "cross-env NODE_ENV=development webpack --progress",
}

... ou vous pouvez créer deux fichiers webpack.config.js différents pour les versions de bureau et mobile, mais je pense que ce qui précède est plus facile ...

Ensuite, npm run devmobile pour créer pour mobile et npm run dev pour ordinateur.

Depuis que je suis sur Windows, j'utilise le cross-envpackage mais c'est la méthode recommandée pour être indépendant du système d'exploitation.

J'utiliserais alors la NormalModuleReplacementPlugin de Webpack:
(basé sur cet exemple )

Dans votre webpack.config.js:

// defining the wanted platform for the build (comfing form the npm run script)
const targetPlatform = process.env.PLATFORM || 'desktop';

// then use the plugin like this
plugins: [
  new webpack.NormalModuleReplacementPlugin(/(.*)-PLATFORM(\.*)/, function(resource) {
    resource.request = resource.request.replace(/-PLATFORM/, `-${targetPlatform}`);
  }),
]

... alors si vous avez ces deux fichiers:

./storage-modules/storage-mobile.js
./storage-modules/storage-desktop.js

importer le nécessaire dans votre script comme ceci:

import './storage-modules/storage-PLATFORM';

De cette manière, la construction générée ne contiendra que le fichier nécessaire à la PLATFORM actuelle utilisée pour le processus de construction.

Une autre solution possible pourrait être le ifdef-loader mais je ne l'ai pas testé. La peine d'essayer semble facile.


Si vous voulez une construction et importez le module nécessaire dynamiquement, vous pouvez faire quelque chose comme ceci dans votre app.js (ou autre chose):

// this needs to have defined when the app is running
const targetPlatform = process.env.PLATFORM || 'desktop';

import(
    /* webpackChunkName: "[request]" */
    `./storage-modules/storage-${targetPlatform}`
).then(storageModule => {
    // use the loaded module
});

ou:

(async () => {
    const storageModule = await import(
        /* webpackChunkName: "[request]" */
        `./storage-modules/storage-${targetPlatform}`
    );
    // use the loaded module
})();

Pour que cela fonctionne, Babel doit être configuré .
Plus d’informations sur Webpack avec importations dynamiques ici .

1
ARS81

Vous pouvez utiliser transform-inline-environment-variables pour passer de plateforme à babel

"build-mobile": "PLATFORM=mobile ...",
"build-app": "PLATFORM=app ...",
0
Jalal