share_this_document plugin page htmlwebpackplugin doc_page cannot body app javascript build conditional require webpack

javascript - plugin - webpack html loader



Construcción condicional basada en el entorno usando Webpack (9)

Tengo algunas cosas para el desarrollo, por ejemplo, simulacros con los que me gustaría no llenar mi archivo de compilación distribuido.

En RequireJS, puede pasar una configuración en un archivo de complemento y, de forma condicional, requerir cosas basadas en eso.

Para webpack no parece haber una forma de hacerlo. En primer lugar, para crear una configuración de tiempo de ejecución para un entorno, he utilizado resolve.alias para resolve.alias un requerimiento dependiendo del entorno, por ejemplo:

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

Luego, al crear la configuración del paquete web, puedo asignar dinámicamente a qué puntos de envsettings archivos apunta (ej. webpackConfig.resolve.alias.envsettings = ''./'' + env ).

Sin embargo, me gustaría hacer algo como:

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

Pero obviamente no quiero construir esos archivos simulados si el entorno no es falso.

Posiblemente podría reenviar manualmente todos esos requisitos a un archivo stub usando resolve.alias nuevamente, pero ¿hay alguna manera que se sienta menos hacky?

¿Alguna idea de cómo puedo hacer eso? Gracias.


Enfrentado con el mismo problema que el OP y requerido, debido a la licencia, para no incluir cierto código en ciertas compilaciones, adopté el webpack-conditional-loader siguiente manera:

En mi comando de compilación establezco una variable de entorno adecuada para mi compilación. Por ejemplo ''demo'' en package.json:

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

La parte confusa que falta en la documentación que leí es que tengo que hacer esto visible durante todo el proceso de compilación asegurándome de que mi variable env se inyecte en el proceso global, por lo tanto, en mi 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};

Con esto en su lugar, puedo excluir condicionalmente cualquier cosa, asegurando que cualquier código relacionado se elimine correctamente del JavaScript resultante. Por ejemplo, en my routes.js, el contenido de demostración se mantiene fuera de otras compilaciones, por lo tanto:

... // #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 ...

Esto funciona con webpack 4.29.6.


He tenido problemas para configurar env en mis configuraciones de webpack. Lo que generalmente quiero es configurar env para que pueda alcanzarse dentro de webpack.config.js , postcss.config.js y dentro de la aplicación de punto de entrada ( index.js generalmente). Espero que mis hallazgos puedan ayudar a alguien.

La solución que se me ocurrió es pasar --env production o --env development , y luego configurar el modo dentro de webpack.config.js . Sin embargo, eso no me ayuda a hacer que env accesible donde lo quiero (ver arriba), por lo que también necesito configurar process.env.NODE_ENV explícitamente, como se recomienda here . La parte más relevante que tengo en webpack.config.js sigue a continuación.

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


No estoy seguro de por qué la respuesta "webpack.DefinePlugin" es la mejor en todas partes para definir las importaciones / requisitos basados ​​en el entorno.

El problema con ese enfoque es que todavía está entregando todos esos módulos al cliente -> verifique con webpack-bundle-analyezer por ejemplo. Y no reduce el tamaño de tu bundle.js en absoluto :)

Entonces, lo que realmente funciona bien y es mucho más lógico es: NormalModuleReplacementPlugin

Entonces, en lugar de hacer un requerimiento condicional on_client -> simplemente no incluye los archivos no necesarios al paquete en primer lugar

Espero que ayude


Otra forma es usar un archivo JS como proxy y dejar que ese archivo cargue el módulo de interés en commonjs y exportarlo como es2015 module , de esta manera:

// file: myModule.dev.js module.exports = "this is in dev" // file: myModule.prod.js module.exports = "this is in prod" // file: myModule.js let loadedModule if(WEBPACK_IS_DEVELOPMENT){ loadedModule = require(''./myModule.dev.js'') }else{ loadedModule = require(''./myModule.prod.js'') } export const myString = loadedModule

Entonces puede usar el módulo ES2015 en su aplicación normalmente:

// myApp.js import { myString } from ''./store/myModule.js'' myString // <- "this is in dev"


Puede usar el complemento define .

Lo uso haciendo algo tan simple como esto en su archivo de compilación de paquete web donde env es la ruta a un archivo que exporta un objeto de configuración:

// 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 };

y luego esto en tu código

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

Eliminará este código de su archivo de compilación si la condición es falsa. Puede ver un ejemplo de compilación de Webpack funcional aquí .


Si bien esta no es la mejor solución, puede funcionar para algunas de sus necesidades. Si desea ejecutar un código diferente en el nodo y el navegador, esto funcionó para mí:

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


Terminé usando algo similar a la respuesta de Matt Derrick , pero estaba preocupado por dos puntos:

  1. La configuración completa se inyecta cada vez que uso ENV (que es malo para configuraciones grandes).
  2. Tengo que definir múltiples puntos de entrada porque require(env) puntos require(env) a diferentes archivos.

Lo que se me ocurrió es un compositor simple que construye un objeto de configuración y lo inyecta en un módulo de configuración.
Aquí está la estructura de archivos, que estoy usando para esto:

config/ └── main.js └── dev.js └── production.js src/ └── app.js └── config.js └── ... webpack.config.js

main.js contiene todas las cosas de configuración predeterminadas:

// main.js const mainConfig = { apiEndPoint: ''https://api.example.com'', ... } module.exports = mainConfig;

dev.js y production.js solo contienen material de configuración que anula la configuración principal:

// dev.js const devConfig = { apiEndPoint: ''http://localhost:4000'' } module.exports = devConfig;

La parte importante es el webpack.config.js que compone la configuración y usa DefinePlugin para generar una variable de entorno __APP_CONFIG__ que contiene el objeto de configuración compuesto:

const argv = require(''yargs'').argv; const _ = require(''lodash''); const webpack = require(''webpack''); // Import all app configs const appConfig = require(''./config/main''); const appConfigDev = require(''./config/dev''); const appConfigProduction = require(''./config/production''); const ENV = argv.env || ''dev''; function composeConfig(env) { if (env === ''dev'') { return _.merge({}, appConfig, appConfigDev); } if (env === ''production'') { return _.merge({}, appConfig, appConfigProduction); } } // Webpack config object module.exports = { entry: ''./src/app.js'', ... plugins: [ new webpack.DefinePlugin({ __APP_CONFIG__: JSON.stringify(composeConfig(ENV)) }) ] };

El último paso ahora es config.js , se ve así (Usando la sintaxis de exportación de importación es6 aquí porque está debajo del paquete web):

const config = __APP_CONFIG__; export default config;

En su app.js ahora puede usar import config from ''./config''; para obtener el objeto de configuración.


Use github.com/nippur72/ifdef-loader . En tus archivos fuente puedes hacer cosas como

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

La configuración del webpack relevante es

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}`, }, }, ], }, // ... };