5
votes

Possibilité de module d'exportation conditionnelle ES6 basé sur process.env.NODE_ENV?

J'ai écrit une bibliothèque d'utilitaires et je souhaite les secouer lorsque mon utilisateur publie son application.

Dans Webpack v4, vous devez créer votre module ES6 pour prendre en charge tree-shaking , mais je souhaite également diviser ma build de développement et ma build de production en différentes

Ce que je veux, c'est exactement comme le module NPM de react:

import { someFunc } from 'my-utility-es';

Cela m'amène à me poser des questions.

Si je fais mon tous les modules utilitaires commonjs , je n'obtiendrai jamais d'arborescence , mon application devient tellement énorme.

Si je fais tous mes modules utilitaires Export statique ES6 , je devrai inclure message de développement dans le code de production .

Et publier deux modules (ex: my-utility et my-utility-es ) n'aideront pas, car en développement, mon code ressemble à ceci:

import { someFunc } from 'my-utility';

mais dans le code de production, je devrai le changer en ceci:

// index.js
'use strict';

if (process.env.NODE_ENV === 'production') {
  module.exports = require('./cjs/react.production.min.js');
} else {
  module.exports = require('./cjs/react.development.js');
}

Comment puis-je résoudre ce problème?

Mise à jour

Pour être plus clair, ma build de développement et ma build de production contiennent un code source différent (par exemple: la version de production a supprimé tous les messages d'erreur) .

Donc, spécifier le mode webpack ne me satisfait pas.


1 commentaires

Vous ne pouvez pas faire trembler l'arborescence en utilisant la syntaxe es5 / commonJS module.exports. Mais comme partagé ci-dessous, vous pouvez utiliser webpack --mode pour supprimer les parties "développement" du code.


3 Réponses :


-1
votes

Tout ce dont vous avez besoin pour résoudre ce problème est d'utiliser le mode a>. Voir Spécifier le mode .

Depuis webpack v4, la spécification du mode configure automatiquement DefinePlugin pour vous:

  const merge = require('webpack-merge');
  const common = require('./webpack.common.js');

  module.exports = merge(common, {
    mode: 'production',
  });

Ils mentionnent React par son nom:

Si vous utilisez une bibliothèque comme react, vous devriez en fait constater une baisse significative de la taille du bundle après l'ajout de ce plugin.


1 commentaires

Désolé, mais cela ne répond pas à ma question, j'ai mis à jour ma question.



2
votes

J'ai trouvé la réponse par moi-même, je pense que la meilleure façon de le faire est d'utiliser les macros babel :

import { createMacro } from 'babel-plugin-macros';

function macro({ references, state, babel }) {
  state.file.path.node.body.forEach(node => {
    if (node.type === 'ImportDeclaration') {
      if (node.source.value.includes('myLibrary/macro')) {
        if (process.env.NODE_ENV === 'production') {
          node.source.value = 'myLibrary/module/production';
        } else {
          node.source.value = 'myLibrary/module/development';
        }
      }
    }
  });

  return { keepImports: true };
}

export default createMacro(macro);

Ma mise en œuvre de macro: p>

import { something } from 'myLibrary/macro';

// In webpack development:
// ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓
// import { something } from 'myLibrary/development';

// In webpack production:
// ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓
// import { something } from 'myLibrary/production';


0 commentaires

1
votes

Voici la meilleure solution que j'ai trouvée, sans obliger l'utilisateur à utiliser les macros Babel ...

Disons:

  • Notre bibliothèque s'appelle crazy-components
  • Il exporte deux composants React appelés ComponentA et ComponentB
  • Les composants utilisent la séparation de code pour effectuer une certaine journalisation en mode de développement uniquement
// rollup.config.js
import copy from 'rollup-plugin-copy';
/* ... other imports ... */

export default {
  input: 'src/index.js',
  /* ... other config ... */
  plugins: [
    /* ... other plugins ... */
    copy({targets: [{src: 'es/package.json', dest: 'dist/esm'}]})
  ]
};

Nous voulons que la bibliothèque:

  1. Soyez tree-shakable, donc si l'utilisateur importe {ComponentA} à partir de 'crazy-components' , le code pour ComponentB ne finit pas dans leur bundle.

  2. Le code de journalisation est supprimé des lots de production.

Solution

1. Bibliothèque de bundles avec Rollup

2. Configurez Rollup pour créer à la fois des versions CJS et ESM dans les versions de production et de développement (versions de production avec code de journalisation supprimé, etc.).

Les versions CJS sont envoyées vers / dist / cjs , ESM construit en / dist / esm . Les fichiers sont appelés crazy-components.prod.min.js et crazy-components.dev.js.

Seules les versions de développement contiennent le code de journalisation (sans expliquer comment faire tout cela, si vous lisez ceci, vous le savez probablement déjà).

3. Créez des points d'entrée pour CJS et ESM comme suit:

// es/package.json
{
  "type": "module"
}
  "exports": {
    ".": {
      "import": "./es/index.js",
      "require": "./index.js"
    },
    "./es": "./es/index.js"
  },

4. Pointez sur les deux points d'entrée dans package.json:

// package.json
{
  "name": "crazy-components",
  "version": "1.0.0",
  "main": "index.js",
  "module": "es/index.js",
  "sideEffects": false
}

5. (facultatif) Rendre importable comme ESM dans NodeJS

Node 12 (avec indicateur) et Node 13+ prend en charge les modules ES nativement .

Ajouter à package.json:

// es/index.js
import {
    ComponentA as ComponentA_prod,
    ComponentB as ComponentA_prod
} from '../dist/esm/crazy-components.prod.min.js';

import {
    ComponentA as ComponentA_dev,
    ComponentB as ComponentA_dev
} from '../dist/esm/crazy-components.dev.js';

export const ComponentA = process.env.NODE_ENV === 'production' ? ComponentA_prod : ComponentA_dev;
export const ComponentB = process.env.NODE_ENV === 'production' ? ComponentB_prod : ComponentB_dev;


0 commentaires