Voorwaardelijke build op basis van omgeving met Webpack

Ik heb een aantal dingen voor ontwikkeling – bijv. mocks waarmee ik mijn gedistribueerde buildbestand niet wil laten opzwellen.

In RequireJS kun je een configuratie in een plug-inbestand doorgeven en op basis daarvan voorwaarden eisen.

Voor webpack lijkt er geen manier te zijn om dit te doen. Ten eerste om een ​​runtime-configuratie voor een omgeving te maken, heb ik resolve.aliasgebruikt om een ​​vereiste opnieuw te verwijzen op het milieu, bijv.:

// All settings.
var all = {
    fish: 'salmon'
};
// `envsettings` is an alias resolved at build time.
module.exports = Object.assign(all, require('envsettings'));

Bij het maken van de webpack-configuratie kan ik dynamisch toewijzen naar welk bestand envsettingsverwijst (dwz webpackConfig.resolve.alias.envsettings = './' + env).

Ik zou echter iets willen doen als:

if (settings.mock) {
    // Short-circuit ajax calls.
    // Require in all the mock modules.
}

Maar ik wil natuurlijk geen nepbestanden inbouwen als de omgeving niet nep is.

Ik zou al die vereisten mogelijk handmatig opnieuw kunnen verwijzen naar een stub-bestand met behulp van resolve.alias – maar is er een manier die minder hacky aanvoelt?

Enig idee hoe ik dat kan doen? Bedankt.


Antwoord 1, autoriteit 100%

Je kunt de define plugingebruiken.

Ik gebruik het door zoiets eenvoudigs te doen in je webpack-buildbestand waarbij envhet pad is naar een bestand dat een object met instellingen exporteert:

// Webpack build config
plugins: [
    new webpack.DefinePlugin({
        ENV: require(path.join(__dirname, './path-to-env-files/', env))
    })
]
// Settings file located at `path-to-env-files/dev.js`
module.exports = { debug: true };

en dan dit in je code

if (ENV.debug) {
    console.log('Yo!');
}

Het zal deze code uit uw buildbestand verwijderen als de voorwaarde onwaar is. Je kunt een werkend voorbeeld van een webpack-build hierzien.


Antwoord 2, autoriteit 84%

Ik weet niet zeker waarom het antwoord “webpack.DefinePlugin” overal de beste is voor het definiëren van op de omgeving gebaseerde importen/vereisten.

Het probleemmet die aanpak is dat je nog steeds al die modules aan de klant levert -> controleer bijvoorbeeld met webpack-bundle-analyezer. En de grootte van je bundel.js helemaal niet verkleinen 🙂

Dus wat echt goed werkt en veel logischer is: NormalModuleReplacementPlugin

Dus in plaats van een on_client voorwaardelijke eis -> voeg in de eerste plaats niet-benodigde bestanden toe aan de bundel

Hoop dat dat helpt


Antwoord 3, autoriteit 63%

Gebruik ifdef-loader. In je bronbestanden kun je dingen doen zoals

/// #if ENV === 'production'
console.log('production!');
/// #endif

De relevante webpack-configuratie is

const preprocessor = {
  ENV: process.env.NODE_ENV || 'development',
};
const ifdef_query = require('querystring').encode({ json: JSON.stringify(preprocessor) });
const config = {
  // ...
  module: {
    rules: [
      // ...
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: {
          loader: `ifdef-loader?${ifdef_query}`,
        },
      },
    ],
  },
  // ...
};

4, Autoriteit 6%

geconfronteerd met hetzelfde probleem als het OP en vereist, vanwege de licenties, niet om bepaalde code in bepaalde builds op te nemen, heb ik de Webpack-conditional-loader als volgt:

In mijn build-opdracht stel ik een omgevingsvariabele op de juiste manier voor mijn build. Bijvoorbeeld ‘Demo’ in Package.json:

...
  "scripts": {
    ...
    "buildDemo": "./node_modules/.bin/webpack --config webpack.config/demo.js --env.demo --progress --colors",
...

Het verwarrende deel dat ontbreekt in de documentatie die ik heb gelezen, is dat ik dit zichtbaar moet maken tijdens het bouwprocesdoor ervoor te zorgen dat mijn env-variabele in het proces global wordt geïnjecteerd, dus in mijn webpack.config /demo.js:

/* The demo includes project/reports action to access placeholder graphs.
This is achieved by using the webpack-conditional-loader process.env.demo === true
 */
const config = require('./production.js');
config.optimization = {...(config.optimization || {}), minimize: false};
module.exports = env => {
  process.env = {...(process.env || {}), ...env};
  return config};

Als dit op zijn plaats is, kan ik alles voorwaardelijk uitsluiten en ervoor zorgen dat alle gerelateerde code op de juiste manier uit het resulterende JavaScript wordt geschud. In mijn routes.js wordt de demo-inhoud bijvoorbeeld buiten andere builds gehouden, dus:

...
// #if process.env.demo
import Reports from 'components/model/project/reports';
// #endif
...
const routeMap = [
  ...
  // #if process.env.demo
  {path: "/project/reports/:id", component: Reports},
  // #endif
...

Dit werkt met webpack 4.29.6.


Antwoord 5, autoriteit 2%

Ik heb moeite met het instellen van env in mijn webpack-configuraties. Wat ik meestal wil, is env zo instellen dat het kan worden bereikt in webpack.config.js, postcss.config.jsen in de toepassing van het toegangspunt zelf (index.jsmeestal). Ik hoop dat mijn bevindingen iemand kunnen helpen.

De oplossing die ik heb bedacht is om --env productionof --env developmentdoor te geven en vervolgens de modus in webpack.config.js.
Dat helpt me echter niet om envtoegankelijk te maken waar ik het wil (zie hierboven), dus ik moet ook process.env.NODE_ENVexpliciet instellen, zoals aanbevolen hier.
Het meest relevante deel dat ik heb in webpack.config.jsvolgt hieronder.

...
module.exports = mode => {
  process.env.NODE_ENV = mode;
  if (mode === "production") {
    return merge(commonConfig, productionConfig, { mode });
  }
  return merge(commonConfig, developmentConfig, { mode });
};

Antwoord 6

Gebruik omgevingsvariabelen om dev- en productimplementaties te maken:

https://webpack.js.org/guides/environment-variables/


Antwoord 7

Hoewel dit niet de beste oplossing is, kan het voor sommige van uw behoeften werken. Als je verschillende code in node en browser wilt gebruiken, werkte dit voor mij:

if (typeof window !== 'undefined') 
    return
}
//run node only code now

Other episodes